From 32036530ac976a3761bf1f14232327398800cd4f Mon Sep 17 00:00:00 2001 From: Miguel Michelson Martinez Date: Sun, 25 Feb 2024 00:22:38 -0300 Subject: [PATCH] specs --- .rubocop.yml | 11 +- app/controllers/messenger/auth_controller.rb | 2 + .../list_renderer/component.html.erb | 1 + app/views/devise/sessions/new.html.erb | 2 +- spec/rails_helper.rb | 22 +- spec/support/system_helpers.rb | 357 ++++++++++ spec/system/app/agent_invitation_spec.rb | 49 ++ spec/system/app/app_packages_spec.rb | 137 ++++ spec/system/app/bot_tasks.rb | 90 +++ spec/system/app/conversations_spec.rb | 82 +++ spec/system/app/login_spec.rb | 94 +++ spec/system/app/settings_spec.rb | 52 ++ spec/system/messenger/app_packages_spec.rb | 232 +++++++ spec/system/messenger/availability_spec.rb | 42 ++ spec/system/messenger/banner_spec.rb | 152 +++++ spec/system/messenger/conversations_spec.rb | 175 +++++ spec/system/messenger/customization_spec.rb | 43 ++ .../system/messenger/event_triggering_spec.rb | 44 ++ spec/system/messenger/privacy_spec.rb | 48 ++ spec/system/messenger/task_bot_spec.rb | 163 +++++ spec/system/messenger/test_spec.rb | 624 ++++++++++++++++++ spec/system/messenger/translations_spec.rb | 103 +++ .../messenger/user_auto_messages_spec.rb | 1 + 23 files changed, 2517 insertions(+), 9 deletions(-) create mode 100644 spec/support/system_helpers.rb create mode 100644 spec/system/app/agent_invitation_spec.rb create mode 100644 spec/system/app/app_packages_spec.rb create mode 100644 spec/system/app/bot_tasks.rb create mode 100644 spec/system/app/conversations_spec.rb create mode 100644 spec/system/app/login_spec.rb create mode 100644 spec/system/app/settings_spec.rb create mode 100644 spec/system/messenger/app_packages_spec.rb create mode 100644 spec/system/messenger/availability_spec.rb create mode 100644 spec/system/messenger/banner_spec.rb create mode 100644 spec/system/messenger/conversations_spec.rb create mode 100644 spec/system/messenger/customization_spec.rb create mode 100644 spec/system/messenger/event_triggering_spec.rb create mode 100644 spec/system/messenger/privacy_spec.rb create mode 100644 spec/system/messenger/task_bot_spec.rb create mode 100644 spec/system/messenger/test_spec.rb create mode 100644 spec/system/messenger/translations_spec.rb create mode 100644 spec/system/messenger/user_auto_messages_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 7bb538cc2..846a4fb4e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -9,13 +9,12 @@ Style/StringLiterals: Enabled: true EnforcedStyle: double_quotes SupportedStyles: - - single_quotes - - double_quotes + - single_quotes + - double_quotes Style/HashSyntax: EnforcedShorthandSyntax: never - Rails/EnvironmentVariableAccess: AllowReads: true @@ -24,7 +23,7 @@ Lint/EmptyBlock: - 'spec/**/*' Metrics/BlockLength: Exclude: - - 'spec/**/*' + - 'spec/**/*' Style/OpenStructUse: Enabled: false @@ -41,6 +40,7 @@ Metrics/ModuleLength: Exclude: - app/helpers/application_helper.rb - app/services/message_apis/helpers.rb + - spec/**/* Rails/InverseOf: Enabled: false @@ -59,6 +59,3 @@ AllCops: - 'tmp/**/*' - 'spec/e2e/**/*' - public/assets/**/* - - - diff --git a/app/controllers/messenger/auth_controller.rb b/app/controllers/messenger/auth_controller.rb index 8f0b0ec67..edbbd8b02 100644 --- a/app/controllers/messenger/auth_controller.rb +++ b/app/controllers/messenger/auth_controller.rb @@ -37,6 +37,8 @@ def create inbound_settings: @app.inbound_settings, inline_conversations: ActiveModel::Type::Boolean.new.cast(@app.inline_new_conversations) } + rescue OriginValidator::NonAcceptedOrigin => e + render json: { error: e.message }, status: :unauthorized end private diff --git a/app/frontend/components/list_renderer/component.html.erb b/app/frontend/components/list_renderer/component.html.erb index bc8214d2f..6daebbe44 100644 --- a/app/frontend/components/list_renderer/component.html.erb +++ b/app/frontend/components/list_renderer/component.html.erb @@ -2,6 +2,7 @@ <% @field.each do |item| %>
+ data-cy="action-<%= item["id"] %>" data-action="<%= action_method(item["action"]) %>" data-field-json="<%= item.to_json %>" <% end %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index cbac2446d..47d0de026 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -46,7 +46,7 @@ <%= form_for(resource, as: resource_name, url: session_path(resource_name), - class: "mt-8 space-y-6", data: {'turbo-frame': '_top' } ) do |f| %> + class: "mt-8 space-y-6", data: {'turbo': false } ) do |f| %>
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index c0e1f72aa..7aebc9a1e 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -54,6 +54,26 @@ metadata[:type] = :view_component end + require "falcon/capybara" + + Capybara.configure do |config| # rubocop:disable Lint/ShadowingOuterLocalVariable + # This forces capybara to create a new server instance for each session/spec: + config.reuse_server = false + + # config.server_port = 5002 + # config.server_host = "localhost" + config.default_max_wait_time = 10 + config.raise_server_errors == false + + config.server = :falcon + config.javascript_driver = :selenium_chrome_headless + + app, = Rack::Builder.parse_file(Rails.root.join("config.ru").to_s) + config.app = app + end + + config.include FeatureHelpers, type: :system + # https://github.com/rspec/rspec-rails/issues/2410 config.include ActiveSupport::Testing::Assertions # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures @@ -101,7 +121,7 @@ metadata[:browser] = true end - config.filter_run_excluding browser: true + # config.filter_run_excluding browser: true config.include Devise::Test::ControllerHelpers, type: :controller # RSpec Rails can automatically mix in different behaviours to your tests diff --git a/spec/support/system_helpers.rb b/spec/support/system_helpers.rb new file mode 100644 index 000000000..064573f34 --- /dev/null +++ b/spec/support/system_helpers.rb @@ -0,0 +1,357 @@ +module FeatureHelpers + def login + visit "/" + fill_in "agent_email", with: "miguelmichelson@gmail.com" + fill_in "agent_password", with: "123456" + click_button "Connect" + end + + def auth0_login + visit "/" + + click_button "Connect Auth0" + expect(page.current_url).to include("https://auth.gocience.com/u/organization") + + fill_in "organizationName", with: "cience-development" + click_on "Continue" + + expect(page.current_url).to include("https://auth.gocience.com/u/login") + + fill_in "username", with: Chaskiq::Config.get("TEST_USER_EMAIL") + fill_in "password", with: Chaskiq::Config.get("TEST_USER_PASSWORD") + click_button "Continue" + + expect(page.current_url).to include("localhost:5002/apps/") + expect(page).to have_content "WELCOME BACK TO CIENCE DEVELOPMENT" + end + + def open_new_messenger(options = {}, sessionless: false) + app_key = app.key + url_params = options[:params] || {} + url_params = url_params.merge(sessionless: sessionless) if sessionless + + visit "/tester/#{app_key}?#{url_params.to_query}" + sleep(2) # Wait for page load, replace with appropriate Capybara wait methods + find("#chaskiq-prime").click if options[:disable_open].blank? + within_frame(find("iframe")) do + yield(page) + end + end + + def start_conversation_from_agent + text = "foobar" + serialized_content = MessageApis::BlockManager.serialized_text(text) + # "{\"blocks\": [{\"key\":\"bl82q\",\"text\":\"#{text}\",\"type\":\"unstyled\",\"depth\":0,\"inlineStyleRanges\":[],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}" + app.start_conversation( + message: { + serialized_content: serialized_content, + html_content: text + }, + from: agent, + participant: app.app_users.last + ) + end + + def add_app_package(app_package) + # require 'app_packages_catalog' + # AppPackagesCatalog.update_all(dev_packages: true) + Plugin.restore_plugins_from_fs + + app_package = AppPackage.find_by(name: app_package) + integration = app.app_package_integrations.new + integration.app_package = app_package + integration.save + end + + def add_home_app(namespace, definitions) + app.update(namespace => definitions) + end + + def add_app_package_to_home(namespace, params) + integration = app.app_package_integrations.first + integration + + app.update( + namespace => [params] + ) + end + + def translations + app.update({ + greetings_es: "Hola amigo", + greetings_en: "hello friend", + + intro_en: "we are here to help", + intro_es: "somos un equipo genial", + + tagline_es: "estamos aqui para ayudarte", + tagline_en: "we are an awesome team" + }) + end + + def bot_task_command(app_key) + default_predicates = [ + { + type: "match", + value: "and", + attribute: "match", + comparison: "and" + } + ] + + attributes = { + "title" => "oother", + "state" => "enabled", + "segments" => [ + { "type" => "match", "value" => "and", "attribute" => "match", "comparison" => "and" }, + { "type" => "string", "value" => %w[Visitor Lead], "attribute" => "type", "comparison" => "in" } + ], + "app_id" => app.id, + # "settings"=>{}, + "paths" => [ + { "id" => "a7ca74ba-91a1-490d-9ee4-4f003f8346c3", "steps" => [{ "step_uid" => "821370d6-ab07-4639-88e0-9189812dc7c0", "type" => "messages", "messages" => [{ "app_user" => { "display_name" => "bot", "email" => "bot@chasqik.com", "id" => 1, "kind" => "agent" }, + "serialized_content" => MessageApis::BlockManager.serialized_text("one"), + # '{"blocks":[{"key":"9oe8n","text":"one","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}', + "html_content" => "--***--" }] }, + { "step_uid" => "e4e824a5-a044-4470-ae2a-6f4c6873688b", "type" => "messages", "messages" => [{ "app_user" => { "display_name" => "bot", "email" => "bot@chasqik.com", "id" => 1, "kind" => "agent" }, + "serialized_content" => MessageApis::BlockManager.serialized_text("two"), + # '{"blocks":[{"key":"9oe8n","text":"two","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}', + "html_content" => "--***--" }] }, + { "step_uid" => "65b23057-fd01-41be-a6a6-ad1dad124560", "type" => "messages", "messages" => [{ "app_user" => { "display_name" => "bot", "email" => "bot@chasqik.com", "id" => 1, "kind" => "agent" }, + "serialized_content" => MessageApis::BlockManager.serialized_text("tree"), + # '{"blocks":[{"key":"9oe8n","text":"tree","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}', + "html_content" => "--***--" }] }, + { "step_uid" => "f6aa3e6e-6279-49a2-8234-2953d4f977a9", "type" => "messages", "messages" => [], "controls" => { "type" => "wait_for_reply", "schema" => [] } }, + { "step_uid" => "aed55b6e-de26-413f-8fc9-975f8c62a4e7", "type" => "messages", "messages" => [{ "app_user" => { "display_name" => "bot", "email" => "bot@chasqik.com", "id" => 1, "kind" => "agent" }, + "serialized_content" => MessageApis::BlockManager.serialized_text("four"), + # '{"blocks":[{"key":"9oe8n","text":"four","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}', + "html_content" => "--***--" }] }], + "title" => "oijioj", "follow_actions" => nil } + ], + "bot_type" => "outbound" + # "position"=>3 + } + + app.bot_tasks.create(attributes) + end + + def app_bot_settings(options) + # frozen_string_literal: true + + Geocoder::Lookup::Test.set_default_stub( + [ + { + "coordinates" => [40.7143528, -74.0059731], + "latitude" => 40.7143528, + "longitude" => -74.0059731, + "address" => "New York, NY, USA", + "state" => "New York", + "city" => "newy york", + "region" => "new_yorke", + "state_code" => "NY", + "country" => "United States", + "country_code" => "US" + } + ] + ) + + # app = FactoryBot.create(:app, + # domain_url: "http://localhost:5002", + # encryption_key: "unodostrescuatro", + # active_messenger: "true", + # state: "enabled") + + agent = app.add_agent({ email: "test@test.cl", name: "sharleena" }) + # user = app.add_user({email: "test@test.cl"}) + + app.update( + timezone: "UTC", + lead_tasks_settings: { + delay: false, + routing: "assign", + email_requirement: "email_only", + assignee: agent.agent.id, + share_typical_time: true + }, + email_requirement: options["email_requirement"], + team_schedule: [ + { day: "tue", from: "01:00", to: "01:30" } + ] + ) + end + + def start_conversation_command(command_options) + ActiveRecord::Base.connection_pool.with_connection do + text = command_options.fetch(:text) || "aaa" + serialized_content = MessageApis::BlockManager.serialized_text(text) + # "{\"blocks\": [{\"key\":\"bl82q\",\"text\":\"#{text}\",\"type\":\"unstyled\",\"depth\":0,\"inlineStyleRanges\":[],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}" + app = App.find_by(key: command_options.fetch(:app_key)) + + app.assignment_rules.create( + title: "test", + agent: app.agents.first, + conditions: command_options.fetch(:rules) || [], + priority: 1 + ) + + app.conversations.first.add_message( + from: app.agents.first, + message: { + html_content: "

ss

", + serialized_content: serialized_content, + text_content: serialized_content + } + ) + end + end + + def new_conversation_bot_task_command(command_options) + default_predicates = [ + { + type: "match", + value: "and", + attribute: "match", + comparison: "and" + } + ] + + attributes = { + "title" => "oother", + "state" => "enabled", + "segments" => [ + { "type" => "string", "value" => "AppUser", "attribute" => "type", "comparison" => "eq" } + ], + "app_id" => 1, + "paths" => [ + { + "id" => "3418f148-6c67-4789-b7ae-8fb3758a4cf9", + "steps" => [ + { + "type" => "messages", + "controls" => { + "type" => "ask_option", + "label" => "migujhijoij", + "schema" => [ + { + "id" => "0dc3559e-4eab-43d9-ab60-7325219a3f6f", + "label" => "see more?", + "element" => "button", + "next_step_uuid" => "73a9d3ec-05f2-4bc9-8fcc-89c51787bb3f" + }, + { + "type" => "messages", + "controls" => { + "type" => "ask_option", + "schema" => [ + { + "id" => "0dc3559e-4eab-43d9-ab60-7325219a3f6f", + "label" => "write here", + "element" => "button" + } + ] + }, + "messages" => [], + "step_uid" => "30e48aed-19c0-4b62-8afa-9a0392deb0b8" + } + ], + "wait_for_input" => true + }, + "messages" => [], + "step_uid" => "30e48aed-19c0-4b62-8afa-9a0392deb0b8" + } + ], + "title" => "uno", + "follow_actions" => nil + }, + { + "id" => "00e9e01a-5af2-4209-a879-85e87fb38c6b", + "steps" => [ + { + "type" => "messages", + "messages" => [ + { + "app_user" => { + "id" => 1, + "kind" => "agent", + "email" => "bot@chasqik.com", + "display_name" => "bot" + }, + "html_content" => "--***--", + "serialized_content" => MessageApis::BlockManager.serialized_text("sauper!") + } + ], + "step_uid" => "73a9d3ec-05f2-4bc9-8fcc-89c51787bb3f" + }, + { + "type" => "messages", + "controls" => { "type" => "wait_for_reply", "schema" => [] }, + "messages" => [], + "step_uid" => "46c92a6e-37e9-4c77-8055-861e80b875bf" + }, + { + "type" => "messages", + "messages" => [ + { + "app_user" => { + "id" => 1, + "kind" => "agent", + "email" => "bot@chasqik.com", + "display_name" => "bot" + }, + "html_content" => "--***--", + "serialized_content" => MessageApis::BlockManager.serialized_text("oh si?") + } + ], + "step_uid" => "26209898-0fb7-48c8-ad4c-356f46ff6c5c" + }, + { + "type" => "messages", + "controls" => { + "type" => "ask_option", + "schema" => [ + { + "id" => "82efa445-d5a4-40a6-a8cf-29c204f016f3", + "label" => "go to!", + "element" => "button", + "next_step_uuid" => "f2e7f51a-5c02-4777-9ef5-f4bba48412c4" + } + ] + }, + "messages" => [], + "step_uid" => "3677eaf3-959c-4b0b-83e1-b1e802df7977" + } + ], + "title" => "dos", + "follow_actions" => nil + }, + { + "id" => "cf6d6018-2922-4b88-b0b7-d0d76e6c18f5", + "steps" => [ + { + "type" => "messages", + "messages" => [ + { + "app_user" => { + "id" => 1, + "kind" => "agent", + "email" => "bot@chasqik.com", + "display_name" => "bot" + }, + "html_content" => "--***--", + "serialized_content" => MessageApis::BlockManager.serialized_text("ah ah !") + } + ], + "step_uid" => "f2e7f51a-5c02-4777-9ef5-f4bba48412c4" + } + ], + "title" => "tres", + "follow_actions" => nil + } + ], + "bot_type" => "new_conversations" + # "position"=>3 + } + + app.bot_tasks.create(attributes) + end +end diff --git a/spec/system/app/agent_invitation_spec.rb b/spec/system/app/agent_invitation_spec.rb new file mode 100644 index 000000000..5db99b552 --- /dev/null +++ b/spec/system/app/agent_invitation_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe "Agent Invitation", type: :system do + let(:agent) { Agent.last } + + let!(:app) do + require "app_packages_catalog" + AppPackagesCatalog.update_all + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled") + end + + before :each do + app = App.last + invited_agent = Agent.invite!(email: "foo@bar.com") # , name: 'John Doe') + role = app.roles.find_or_initialize_by(agent_id: invited_agent.id) + role.save + end + + it "Sign in view" do + # Generate the invitation token + agent.send :generate_invitation_token! + token = agent.raw_invitation_token + + visit "/agents/invitation/accept?invitation_token=#{token}" + expect(page).to have_selector('input[placeholder="Type your password"]') + + fill_in "agent_password", with: "123456" + fill_in "agent_password_confirmation", with: "123456" + click_on "Set my password" + expect(page).to have_content("my app") + end + + it "validates password match" do + # Generate the invitation token + agent.send :generate_invitation_token! + token = agent.raw_invitation_token + + visit "/agents/invitation/accept?invitation_token=#{token}" + expect(page).to have_selector('input[placeholder="Type your password"]') + + fill_in "agent_password", with: "123456" + fill_in "agent_password_confirmation", with: "1234567" + click_on "Set my password" + expect(page).to have_content("Password confirmation doesn't match Password") + end +end diff --git a/spec/system/app/app_packages_spec.rb b/spec/system/app/app_packages_spec.rb new file mode 100644 index 000000000..02003de4f --- /dev/null +++ b/spec/system/app/app_packages_spec.rb @@ -0,0 +1,137 @@ +require "rails_helper" + +RSpec.describe "AppPackages", type: :system do + let!(:app) do + require "app_packages_catalog" + AppPackagesCatalog.update_all + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled") + end + + let!(:agent_role) do + app.add_admin({ + email: "miguelmichelson@gmail.com", + name: "test agent", + role: "admin", + password: 123_456, + password_confirmation: 123_456 + }) + end + + before :each do + # Replace with the Ruby equivalent of the setup code + # Example: Plugin.restore_plugins_from_fs + Plugin.restore_plugins_from_fs + end + + context "when managing AppPackages" do + before do + # Login and other setup before each test + + # Replace with Ruby equivalent of cy.appEval + # Example: Update roles for an Agent + end + + it "denies access for non-admin roles" do + app.roles.map { |o| o.update(role: "agent") } + app.key + + login + + # visit '/apps' + find("a", text: "my app").click + # sleep(2) # Replace with Capybara wait mechanisms if possible + find("a[aria-label='Settings']").click + expect(page).to have_content("Access denied") + end + + it "allows access and displays settings for admin roles" do + # Additional setup for admin role if needed + + app.roles.map { |o| o.update(role: "admin_only") } + login + # visit '/apps' + find("a", text: "my app").click + + find("a[aria-label='Settings']").click + expect(page).to have_content("App Settings") + expect(page).to have_content("Team") + expect(page).to have_content("Integrations") + + click_on("Integrations") + expect(page).to have_content("Third party integrations") + end + end + + context "when adding AppPackages" do + before do + App.last.update(owner_id: agent_role.agent.id) + end + + it "adds AppPackages" do + login + + find("a", text: "my app").click + + find("a[aria-label='Settings']").click + expect(page).to have_content("Integrations") + + click_on("Integrations") + click_on("Available API's") + find("[data-cy=services-reveniu-add]").click + + click_on("Save") + expect(page).to have_content("Updated successfully") + end + + it "manages home apps app packages" do + app.roles.map { |o| o.update(role: "admin_only") } + + login + + # visit '/apps' + find("a", text: "my app").click + # sleep(0.5) # Consider replacing with Capybara's wait mechanisms + + find("a[aria-label='Settings']").click + sleep(0.5) # Consider replacing with Capybara's wait mechanisms + + click_on("Messenger Settings") + sleep(0.5) # Consider replacing with Capybara's wait mechanisms + + click_on("Apps") + expect(page).to have_content("Add apps to your Messenger") + find("a", text: "Add app").click + + expect(page).to have_content("Send App Package") + + find('button[data-cy="add-package-ContentShowcase"]').click + + # Find and click on the ContentShowcase element's corresponding button + # within(find(".content-showcase-selector")) do + # find("button").click + # end + + expect(page).to have_content("Pick a template") + + find('div[data-cy="action-announcement"]').click + + # click_on("Announcement") + + click_on("Customize") + + fill_in "heading", with: "Hello, World" + fill_in "page_url", with: "https://github.com/rails/rails" + click_on("autofill inputs with page details") + + # Wait for the fields to be auto-filled + expect(page).to have_field("title", with: "GitHub - rails/rails: Ruby on Rails") + expect(find('input[name="cover_image"]').value).to be_present + + click_on("Add to messenger home") + # Further actions or assertions as needed + end + end +end diff --git a/spec/system/app/bot_tasks.rb b/spec/system/app/bot_tasks.rb new file mode 100644 index 000000000..ffd253a74 --- /dev/null +++ b/spec/system/app/bot_tasks.rb @@ -0,0 +1,90 @@ +require "rails_helper" + +RSpec.describe "Bot Tasks", type: :system do + let!(:app) do + require "app_packages_catalog" + AppPackagesCatalog.update_all + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled") + end + + let!(:agent_role) do + app.add_admin({ + email: "miguelmichelson@gmail.com", + name: "test agent", + role: "admin", password: 123_456, password_confirmation: 123_456 + }) + end + + let!(:app_user) do + # Additional setup to mimic cy.appEval for conversation creation + App.last.add_user( + email: "test@test2.cl", + name: "ebola boli", + first_name: "some user" + ) + end + + before :each do + App.last.start_conversation( + message: { + text_content: "hi from test backend", + serialized_content: MessageApis::BlockManager.serialized_text("some text from backend") + }, + from: app_user + ) + end + + it "Insert AppPackages" do + login + # visit '/apps' + find("a", text: "my app").click + find("a[aria-label='Routing Bots']", visible: false).click(force: true) + + expect(page).to have_content("Outbound") + expect(page).to have_content("New Conversations") + expect(page).to have_content("Bot Tasks") + + click_on("Outbound") + click_on("Create New Task") + + fill_in "bot_task_title", with: "my super task" + find('[data-cy="bot-task-create"]').click + + click_on("Editor") + + click_on("Add New") + find('input[placeholder="write path title"]').set("foo") + find('[data-cy="bot-task-create-path"]').click + + click_on("foo") + + click_on("Add App") + find("[data-cy=add-package-ContentShowcase]").click + + expect(page).to have_content("Pick a template") + # click_on('Announcement') + all(".list-item").first.click + + click_on("Customize") + + fill_in "heading", with: "Hello, World" + fill_in "page_url", with: "https://github.com/rails/rails" + click_on("autofill inputs with page details") + + expect(page).to have_field("title", with: "GitHub - rails/rails: Ruby on Rails") + expect(find('input[name="cover_image"]').value).to be_present + + click_on("Add to messenger home") + + click_on("Send App") + + # Using a custom wait logic to ensure the 'Send App' button is not disabled + expect(page).to have_no_content("Send App") + + # find('[data-cy=send-app-ContentShowcase]').click + expect(page).to have_content("Hello, World") + end +end diff --git a/spec/system/app/conversations_spec.rb b/spec/system/app/conversations_spec.rb new file mode 100644 index 000000000..0786afe22 --- /dev/null +++ b/spec/system/app/conversations_spec.rb @@ -0,0 +1,82 @@ +require "rails_helper" + +RSpec.describe "Conversations Spec", type: :system do + let!(:app) do + require "app_packages_catalog" + AppPackagesCatalog.update_all + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled") + end + + let!(:agent_role) do + app.add_admin({ + email: "miguelmichelson@gmail.com", + name: "test agent", + role: "admin", password: 123_456, password_confirmation: 123_456 + }) + end + + let!(:app_user) do + # Additional setup to mimic cy.appEval for conversation creation + App.last.add_user( + email: "test@test2.cl", + name: "ebola boli", + first_name: "some user" + ) + end + + before :each do + # Mimic the appEval setup from Cypress + App.last.start_conversation( + message: { + text_content: "hi from test backend", + serialized_content: MessageApis::BlockManager.serialized_text("some text from backend") + }, + from: app_user + ) + end + + it "Send app package on conversation" do + login + find("a", text: "my app").click + + find("a[aria-label='Conversations']").click(force: true) + + first("[data-cy=conversation-item]").click(force: true) + expect(page).to have_content("some text from backend") + + find("[contenteditable]").click + find("[contenteditable]").set('foo \r\n') + + find("[data-cy=inline-tooltip-button-AppPackage]").click + find("[data-cy=add-package-ContentShowcase]").click + + expect(page).to have_content("Pick a template") + + all(".list-item").first.click + click_on("Customize") + + fill_in "heading", with: "Hello, World" + fill_in "page_url", with: "https://github.com/rails/rails" + click_on("autofill inputs with page details") + + # Use Capybara's wait mechanism instead of sleep + expect(page).to have_field("title", with: "GitHub - rails/rails: Ruby on Rails") + + # Use matcher to check if input value is present + expect(find("input[name=cover_image]").value).to be_present + + click_on("Add to messenger home") + + # Use Capybara's wait mechanism to check for absence of content + expect(page).to have_no_content("Send App") + + find("[data-cy=send-app-ContentShowcase]").click + + # Expectations after clicking 'Send App' + expect(page).to have_content("HELLO, WORLD") + expect(page).to have_content("CONTENTSHOWCASE") + end +end diff --git a/spec/system/app/login_spec.rb b/spec/system/app/login_spec.rb new file mode 100644 index 000000000..d6800aa67 --- /dev/null +++ b/spec/system/app/login_spec.rb @@ -0,0 +1,94 @@ +require "rails_helper" +require "sidekiq/testing" + +RSpec.describe "Widget management", type: :system do + let!(:app) do + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled") + end + + let!(:user) do + app.add_user({ email: "test2@test.cl" }) + end + + let!(:agent_role) do + app.add_agent({ email: "miguel.michelson@cience.com", name: "test agent" }) + end + + let(:assignment_rule) do + lambda { |rules| + app.assignment_rules.create({ + title: "test", + agent: agent_role.agent, + conditions: rules || [], + priority: 1 + }) + } + end + + let(:user_auto_message) do + FactoryBot.create(:user_auto_message, app: app) + end + + def serialized_content(text = "foobar") + "{\"blocks\": [{\"key\":\"bl82q\",\"text\":\"#{text}\",\"type\":\"unstyled\",\"depth\":0,\"inlineStyleRanges\":[],\"entityRanges\":[],\"data\":{}}],\"entityMap\":{}}" + end + + def setting_for_user( + enabled: false, + users: true, + user_segment: "all", + user_options: [], + visitors: true, + visitor_options: [], + visitor_segment: "all" + ) + settings = { + "enabled" => enabled, + "users" => { "enabled" => users, "segment" => user_segment, "predicates" => user_options }, + "visitors" => { "enabled" => visitors, "segment" => visitor_segment, "predicates" => visitor_options } + } + app.update(inbound_settings: settings) + end + + before do + if ENV["CI"].present? + # Selenium::WebDriver::Chrome::Service.driver_path = ENV.fetch('GOOGLE_CHROME_BIN', nil) + # options = Selenium::WebDriver::Chrome::Options.new + # options.binary = ENV.fetch('GOOGLE_CHROME_SHIM', nil) + # driver = Selenium::WebDriver.for :chrome, options: options + + Capybara.register_driver :chrome do |app| + options = Selenium::WebDriver::Chrome::Options.new(args: %w[no-sandbox headless disable-gpu]) + Capybara::Selenium::Driver.new(app, browser: :chrome, options: options) + end + end + + options_for_selemium = if ENV["CI"].present? + { + args: %w[no-sandbox headless disable-gpu] + } + else + { + # args: %w[auto-open-devtools-for-tabs] + } + end + + driven_by :selenium, using: :chrome, screen_size: [1400, 1400], + options: options_for_selemium + + ActiveJob::Base.queue_adapter = :test + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + # Rails.application.config.active_job.queue_adapter = :test + end + + context "translations" do + before :each do + end + + it "login view" do + login + end + end +end diff --git a/spec/system/app/settings_spec.rb b/spec/system/app/settings_spec.rb new file mode 100644 index 000000000..1253fffcc --- /dev/null +++ b/spec/system/app/settings_spec.rb @@ -0,0 +1,52 @@ +require "rails_helper" + +RSpec.describe "Settings Spec", type: :system do + let!(:app) do + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled") + end + + let!(:agent_role) do + app.add_admin({ + email: "miguelmichelson@gmail.com", + name: "test agent", + role: "admin", password: 123_456, password_confirmation: 123_456 + }) + end + + it "Team view + invite view" do + login + # visit '/apps' + find("a", text: "my app").click + + find("a[aria-label='Settings']").click(force: true) + expect(page).to have_content("App Settings") + expect(page).to have_content("Messenger Settings") + expect(page).to have_content("Integrations") + expect(page).to have_content("Webhooks") + expect(page).to have_content("API Access") + + click_on("Team") + + expect(page).to have_content("EMAIL") + # expect(page).to have_content('Owner') + + expect(page).to have_content("ACCESS LIST") + expect(page).to have_content("ACTIONS") + + expect(page).to have_selector("div", text: "chaskiq bot") + + expect(page).to have_selector("a", text: "edit link") + expect(page).to have_selector("button", text: "remove") + + expect(page).to have_selector("div", text: "miguelmichelson@gmail.com") + expect(page).to have_selector("div", text: "miguel") + + click_on("Invitations") + + expect(page).to have_content("EMAIL") + expect(page).to have_content("ACTIONS") + expect(page).to have_content("Add Team Member") + end +end diff --git a/spec/system/messenger/app_packages_spec.rb b/spec/system/messenger/app_packages_spec.rb new file mode 100644 index 000000000..0b1323d38 --- /dev/null +++ b/spec/system/messenger/app_packages_spec.rb @@ -0,0 +1,232 @@ +require "rails_helper" + +RSpec.describe "Visitor Home Apps", type: :system, js: true do + let!(:app) do + Plugin.restore_plugins_from_fs + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled", + domain_url: "*") + end + + let!(:agent_role) do + app.add_admin({ email: "miguel.michelson@cience.com", name: "test agent", role: "admin" }) + end + + before :each do + # Set up for ActiveJob, similar to cy.appEval('ActiveJob::Base.queue_adapter = :test') + ActiveJob::Base.queue_adapter = :test + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + end + + it "user session home app" do + # Replicate the addHomeApp functionality. + # This includes updating the app's `user_home_apps` attribute with the provided JSON. + + app.update( + user_home_apps: [ + { + "definitions" => [ + { "type" => "separator" }, + { "type" => "text", "style" => "header", "text" => "hola!" }, + { "type" => "separator" }, + { "type" => "list", "disabled" => false, + "items" => [ + { + "type" => "item", + "id" => "list-item-1", + "title" => "Welcome to Chaskiq mr user", + "subtitle" => "Chaskiq is a 100 open source conversational platform for sales & support", + "image" => "http://app.chaskiq.test:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBYzg9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--bd639808dc87cfad87bef06c9838a40a562cd3e5/foo-1599423116.jpg", + "action" => { "type" => "url", "url" => "https://chaskiq.io" } + } + ] } + ], + "id" => "3", "name" => "ContentShowcase" + } + ] + ) + + # Visit the specific app testing page. + open_new_messenger({ params: { lang: "en" } }, sessionless: false) do |page| + expect(page).to have_content("Welcome to Chaskiq mr user") + end + end + + it "sessionless home app" do + app.update( + visitor_home_apps: [ + { + "definitions" => [ + { "type" => "separator" }, + { "type" => "text", "style" => "header", "text" => "hola!" }, + { "type" => "separator" }, + { "type" => "list", "disabled" => false, + "items" => [ + { + "type" => "item", + "id" => "list-item-1", + "title" => "Welcome to Chaskiq mr anonimous", + "subtitle" => "Chaskiq is a 100 open source conversational platform for sales & support", + "image" => "http://app.chaskiq.test:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBYzg9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--bd639808dc87cfad87bef06c9838a40a562cd3e5/foo-1599423116.jpg", + "action" => { "type" => "url", "url" => "https://chaskiq.io" } + } + ] } + ], + "id" => "3", "name" => "ContentShowcase" + } + ] + ) + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content("Welcome to Chaskiq mr anonimous") + end + end + + it "add package, test click" do + add_app_package("UiCatalog") + app.update( + visitor_home_apps: [ + { + "name" => "UiCatalog", + "definitions" => [ + { + "name" => "bubu", + "label" => "Click this action", + "type" => "button", + "action" => { + "type" => "submit" + } + } + ] + } + ] + ) + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content("Click this action") + find_button("Click this action", match: :first).click + expect(page).to have_content("yes!!!!!") + end + end + + it "add package, test content" do + add_app_package("UiCatalog") + + app.update( + visitor_home_apps: [ + { + "name" => "UiCatalog", + "definitions" => [ + { + "id" => "oli", + "name" => "bubu", + "label" => "Click this action", + "type" => "button", + "action" => { + "type" => "content", + "content_url" => "/internal/ui_catalog" + } + } + ] + } + ] + ) + + translations + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_button("Click this action") + page.find_button("Click this action", match: :first).click + expect(page).to have_content("dynamic") + page.find("#ubu").click # Update this selector based on the actual content + expect(page).to have_content("yes!!!!!") + end + end + + it "add package, frame 1" do + add_app_package("UiCatalog") + app.update( + visitor_home_apps: [ + { + "name" => "UiCatalog", + "definitions" => [ + { + "id" => "da", + "name" => "bubu", + "label" => "Click this action", + "type" => "button", + "action" => { + "type" => "content", + "content_url" => "/internal/ui_catalog" + } + }, + { + "type" => "list", + "disabled" => false, + "items" => [ + { + "type" => "item", + "id" => "slug", + "title" => "a title", + "subtitle" => "subtitle", + "action" => { + "type" => "frame", + "url" => "/package_iframe_internal/UiCatalog" + } + } + ] + } + ] + } + ] + ) + + translations + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content("hello friend") + end + end + + it "add package, frame" do + add_app_package("UiCatalog") + add_app_package_to_home("user_home_apps", { + name: "UiCatalog", + definitions: [ + { + id: "da", + name: "bubu", + label: "Click this action", + type: "button", + action: { + type: "content", + content_url: "/internal/ui_catalog" + } + }, + { + type: "list", + disabled: false, + items: [ + { + type: "item", + id: "slug", + title: "a title", + subtitle: "subtitle", + action: { + type: "frame", + url: "/package_iframe_internal/UiCatalog" + } + } + ] + } + ] + }) + + translations + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content("hello friend") + end + end +end diff --git a/spec/system/messenger/availability_spec.rb b/spec/system/messenger/availability_spec.rb new file mode 100644 index 000000000..577af6bde --- /dev/null +++ b/spec/system/messenger/availability_spec.rb @@ -0,0 +1,42 @@ +require "rails_helper" + +RSpec.describe "Availability Spec", type: :system, js: true do + before do + # Setup ActiveJob similar to Cypress + ActiveJob::Base.queue_adapter = :test + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + end + + it "couple of hours" do + # Setup basic app scenario + # ... + + # Calculate the time for schedule setup + now = Time.current + weekday = I18n.l(now, format: "%a").downcase + start_time = (now + 1.hour).strftime("%H:%M") + end_time = (now + 1.hour + 15.minutes).strftime("%H:%M") + + # Update the app's schedule + App.last.update( + timezone: "UTC", + team_schedule: [{ day: weekday, from: start_time, to: end_time }] + ) + + app = App.last + visit "/tester/#{app.key}?lang=en" + + # Interact with the content inside the iframe + within_frame(find("iframe:first")) do + find("#chaskiq-prime").click + expect(page).to have_content("approximately") + end + + # Repeat the visit and check for the Spanish language + visit "/tester/#{app.key}?lang=es" + within_frame(find("iframe")) do + find("#chaskiq-prime").click + expect(page).to have_content("aprox") + end + end +end diff --git a/spec/system/messenger/banner_spec.rb b/spec/system/messenger/banner_spec.rb new file mode 100644 index 000000000..a17007cdc --- /dev/null +++ b/spec/system/messenger/banner_spec.rb @@ -0,0 +1,152 @@ +require "rails_helper" + +RSpec.describe "Banners Spec", type: :system, js: true do + let(:app_key) { App.last.key } + + let!(:app) do + Plugin.restore_plugins_from_fs + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled", + domain_url: "*") + end + + let!(:agent) do + agent = app.add_agent({ + email: "test@test.cl", + name: "sharleena", + password: "123456", + password_confirmation: "123456" + }, + role_attrs: { + role: "admin" + }) + agent.agent + end + + def banner_command(options) + # frozen_string_literal: true + message = options[:serialized_content] + + serialized_content = MessageApis::BlockManager.serialized_text(message) + + message = FactoryBot.create(:banner, + serialized_content: serialized_content, + app: app, + segments: nil, # app.segments.first.predicates, + scheduled_at: 2.days.ago, + scheduled_to: 30.days.from_now, + settings: options) + + message.enable! + end + + before do + # Setup basic app scenario + # ... + end + + it "will open, hidden on next visit" do + # Setup banner command + # ... + + banner_command({ + serialized_content: "tatecallaoe", + app_key: app_key, + url: "", + mode: "inline", + bg_color: "#bd10e0", + placement: "top", + action_text: "action", + show_sender: "", + dismiss_button: "true", + hidden_constraints: ["open"] + }) + + visit "/tester/#{app_key}" + sleep(3) # Replace with appropriate wait_for_ajax or similar helper if available + + within_frame(find("iframe[data-cy=banner-wrapper]")) do + expect(page).to have_button("action", type: "submit") + end + + visit "/tester/#{app_key}" + expect(page).not_to have_css("iframe[data-cy=banner-wrapper]") + end + + it "will click, hidden on next visit" do + banner_command({ + serialized_content: "tatecallaoe", + app_key: app_key, + url: "", + mode: "inline", + bg_color: "#bd10e0", + placement: "top", + action_text: "action", + show_sender: "", + dismiss_button: "true", + hidden_constraints: ["click"] + }) + + visit "/tester/#{app_key}" + sleep(3) + + within_frame(find("iframe[data-cy=banner-wrapper]")) do + expect(page).to have_button("action", type: "submit") + end + + visit "/tester/#{app_key}" + expect(page).not_to have_css("iframe[data-cy=banner-wrapper]") + end + + it "will open and close button" do + banner_command({ + serialized_content: "tatecallaoe", + app_key: app_key, + url: "", + mode: "inline", + bg_color: "#bd10e0", + placement: "top", + action_text: "action", + show_sender: "", + dismiss_button: "true", + hidden_constraints: ["close"] + }) + + visit "/tester/#{app_key}" + sleep(3) + + within_frame(find("iframe[data-cy=banner-wrapper]")) do + find(".dismiss-button").click + end + + visit "/tester/#{app_key}" + expect(page).not_to have_css("iframe[data-cy=banner-wrapper]") + end + + it "will open and keep open" do + banner_command({ + serialized_content: "tatecallaoe", + app_key: app_key, + url: "", + mode: "inline", + bg_color: "#bd10e0", + placement: "top", + action_text: "Action", + show_sender: "", + dismiss_button: "true", + hidden_constraints: ["close"] + }) + + visit "/tester/#{app_key}" + sleep(3) + + within_frame(find("iframe[data-cy=banner-wrapper]")) do + expect(page).to have_button("Action", type: "submit") + end + + visit "/tester/#{app_key}" + expect(page).to have_css("iframe[data-cy=banner-wrapper]") + end +end diff --git a/spec/system/messenger/conversations_spec.rb b/spec/system/messenger/conversations_spec.rb new file mode 100644 index 000000000..950a3e0da --- /dev/null +++ b/spec/system/messenger/conversations_spec.rb @@ -0,0 +1,175 @@ +require "rails_helper" + +RSpec.describe "Conversation Spec", type: :system, js: true do + let!(:app) do + # Plugin.restore_plugins_from_fs + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled", + domain_url: "*") + end + + let!(:agent) do + agent = app.add_agent({ + email: "test@test.cl", + name: "sharleena", + password: "123456", + password_confirmation: "123456" + }, + role_attrs: { + role: "admin" + }) + agent.agent + end + + let!(:app_user) do + app.add_user(email: "test@test.cl") + end + + before do + # Setup basic app scenario + # ... + end + + describe "run previous" do + it "run previous conversations" do + start_conversation_from_agent + + open_new_messenger({ params: { lang: "en" } }) do |page| + expect(page).to have_content("Start a conversation") + expect(App.last.app_users.size).to eq(1) + expect(page).to have_content("a few seconds ago") + + find("#conversations-list a").click + expect(page).to have_content("foobar") + + find("textarea").set("oeoe").native.send_keys(:return) + expect(page).to have_content("oeoe") + end + end + end + + describe "open conversation blocked replies" do + it "will show cta for new conversation, replies blocked" do + start_conversation_from_agent + + Conversation.last.close! + + app.update(inbound_settings: { + "enabled" => true, + "users" => { + "enabled" => true, + "enabled_inbound" => true, + "segment" => "some", + "close_conversations_enabled" => true, + "close_conversations_after" => 0 + }, + "visitors" => { + "visitors_enable_inbound" => true, + "enabled" => true, + "enabled_inbound" => true, + "segment" => "all", + "close_conversations_after" => -1 + } + }) + + open_new_messenger({ params: { lang: "en" } }) do |page| + # expect(page).to have_content('a few seconds ago') + page.find("#conversations-list a").click + expect(page).to have_content("foobar") + expect(page).to have_content("This conversation has ended") + + page.click_link("Start a conversation") + end + end + + it "will show cta for conversation closed, replies blocked" do + start_conversation_from_agent + + app.update(inbound_settings: { + "enabled" => true, + "users" => { + "enabled" => true, + "enabled_inbound" => true, + "segment" => "some", + "close_conversations_enabled" => true, + "close_conversations_after" => 0 + }, + "visitors" => { + "enabled_inbound" => true, + "enabled" => true, + "segment" => "all", + "close_conversations_after" => -1 + } + }) + + visit "/tester/#{App.last.key}" + + open_new_messenger({ params: { lang: "en" } }) do |page| + expect(page).to have_content("a few seconds ago") + + page.find("#conversations-list a").click + expect(page).to have_content("foobar") + + # Simulate closing the conversation from the backend + Conversation.last.close! + + expect(page).to have_content("This conversation has ended") + expect(page).to have_content("Start a conversation") + end + end + + it "will show textarea" do + start_conversation_from_agent + + app.update(inbound_settings: { + "enabled" => true, + "users" => { + "enabled" => true, + "enabled_inbound" => true, + "segment" => "some", + "close_conversations_enabled" => false, + "close_conversations_after" => 0 + }, + "visitors" => { + "enabled_inbound" => true, + "visitors_enable_inbound" => true, + "enabled" => true, + "segment" => "all", + "close_conversations_after" => -1 + } + }) + + open_new_messenger({ params: { lang: "en" } }) do |page| + expect(page).to have_content("a few seconds ago") + page.find("#conversations-list a").click + page.find("textarea").set("1234").send_keys(:return) + expect(page).to have_content("1234") + end + end + end + + describe "basic" do + it "start_conversation" do + open_new_messenger({ params: { lang: "en" } }) do |page| + expect(page).to have_content("Start a conversation") + + page.find(:xpath, "/html/body/div/div/div/div[2]/div[1]/div[1]/div/div/div/div[2]/div[2]/a[1]").click + textarea = page.find("textarea") + expect(textarea).to be_visible + + textarea.set("oeoe") + # expect(page).to have_content('oeoe') + + # start_conversation_command({ + # text: '11111', + # app_key: app.key, + # rules: [], + # }) + + textarea.set("oeoe").native.send_keys :return + end + end + end +end diff --git a/spec/system/messenger/customization_spec.rb b/spec/system/messenger/customization_spec.rb new file mode 100644 index 000000000..156dac360 --- /dev/null +++ b/spec/system/messenger/customization_spec.rb @@ -0,0 +1,43 @@ +require "rails_helper" + +RSpec.describe "Customization Spec", type: :system, js: true do + let!(:app) do + Plugin.restore_plugins_from_fs + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled", + domain_url: "*") + end + + before do + ActiveJob::Base.queue_adapter = :test + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + # Setup basic app scenario + # ... + end + + it "display colourful" do + app.update(customization_colors: { primary: "#0f0", secondary: "#f00" }) + + open_new_messenger({ params: { lang: "en" } }) do |_page| + expect(app.customization_colors).to be_present + end + end + + it "display default" do + app.update(customization_colors: nil) + + open_new_messenger({ params: { lang: "en" } }) do |_page| + expect(app.customization_colors).to be_nil + end + end + + it "display default on secondary color" do + app.update(customization_colors: { primary: "#0f0", pattern: "https://..." }) + + open_new_messenger({ params: { lang: "en" } }) do |_page| + expect(app.customization_colors).to be_present + end + end +end diff --git a/spec/system/messenger/event_triggering_spec.rb b/spec/system/messenger/event_triggering_spec.rb new file mode 100644 index 000000000..fc494bf23 --- /dev/null +++ b/spec/system/messenger/event_triggering_spec.rb @@ -0,0 +1,44 @@ +require "rails_helper" + +RSpec.describe "Event Triggering", type: :system, js: true do + let!(:app) do + Plugin.restore_plugins_from_fs + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled", + domain_url: "*") + end + + before do + # Setup for ActiveJob and any other initial conditions + ActiveJob::Base.queue_adapter = :test + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + end + + it "wakeup & toggle method" do + visit "/tester/#{app.key}" + + # open_new_messenger({params: { lang: 'en' }}) do |page| + # The following steps simulate the Cypress steps within the iframe context + # Note that direct execution of custom JS commands may vary in Capybara + + sleep(2) + # Execute 'wakeup' command + page.execute_script("window.chaskiqMessenger.sendCommand('wakeup', {})") + sleep(1) # Wait for any changes to take effect + + # Assert the frame-wrapper data attribute to be true + expect(page).to have_css("#frame-wrapper[data-open='true']") + + # Execute 'toggle' command + page.execute_script("window.chaskiqMessenger.sendCommand('toggle', {})") + sleep(1) # Wait for any changes to take effect + + # Assert the frame-wrapper data attribute to be false + + # expect(page).to have_css("#frame-wrapper[data-open='false']") + expect(page.body.include?('
enabled, + "users" => { "enabled" => users, "segment" => user_segment, "predicates" => user_options }, + "visitors" => { "enabled" => visitors, "segment" => visitor_segment, "predicates" => visitor_options } + } + app.update(inbound_settings: settings) + end + + before do + if ENV["CI"].present? + # Selenium::WebDriver::Chrome::Service.driver_path = ENV.fetch('GOOGLE_CHROME_BIN', nil) + # options = Selenium::WebDriver::Chrome::Options.new + # options.binary = ENV.fetch('GOOGLE_CHROME_SHIM', nil) + # driver = Selenium::WebDriver.for :chrome, options: options + + Capybara.register_driver :chrome do |app| + options = Selenium::WebDriver::Chrome::Options.new(args: %w[no-sandbox headless disable-gpu]) + Capybara::Selenium::Driver.new(app, browser: :chrome, options: options) + end + end + + options_for_selemium = if ENV["CI"].present? + { + args: %w[no-sandbox headless disable-gpu] + } + else + { + # args: %w[auto-open-devtools-for-tabs] + } + end + + driven_by :selenium, using: :chrome, screen_size: [1400, 1400], + options: options_for_selemium + + ActiveJob::Base.queue_adapter = :test + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + # Rails.application.config.active_job.queue_adapter = :test + end + + describe "translations" do + before :each do + app.update({ + greetings_es: "Hola amigo", + greetings_en: "hello friend", + + intro_en: "we are here to help", + tagline_en: "estamos aqui para ayudarte", + + intro_es: "somos un equipo genial", + tagline_es: "we are an awesome team" + }) + end + it "english default" do + ClientTesterController.any_instance.stub(:user_options) do + { email: "test@test.cl", + identifier_key: OpenSSL::HMAC.hexdigest("sha256", app.encryption_key, "test@test.cl"), + properties: { + name: "miguel", + lang: "en", + id: "localhost", + country: "chile", + role: "admin", + pro: true + } } + end + + open_new_messenger({ params: { lang: "en" } }, sessionless: false) do |page| + expect(page).to have_content(app.greetings_en) + expect(page).to have_content(app.intro_en) + end + end + + it "spanish will render spanish greeting" do + ClientTesterController.any_instance.stub(:user_options) do + { email: "test@test.cl", + identifier_key: OpenSSL::HMAC.hexdigest("sha256", app.encryption_key, "test@test.cl"), + properties: { + name: "miguel", + lang: "es", + id: "localhost", + country: "chile", + role: "admin", + pro: true + } } + end + + open_new_messenger({ params: { lang: "en" } }, sessionless: false) do |page| + expect(page).to have_content(app.greetings_es) + expect(page).to have_content(app.intro_es) + end + end + + it "english sessionless default" do + ClientTesterController.any_instance.stub(:configured_lang) { "en" } + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content(app.greetings_en) + expect(page).to have_content(app.intro_en) + end + end + + it "spanish sessionless" do + ClientTesterController.any_instance.stub(:configured_lang) { "es" } + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content(app.greetings_es) + expect(page).to have_content(app.intro_es) + end + end + end + + describe "anonimous user" do + ## OKOK + it "renders messenger on anonimous user creating a app user" do + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + expect(page).to have_content("Start a conversation") + end + + user = app.app_users.last + + expect(app.app_users.count).to be == 2 + expect(user.properties).to_not be_blank + expect(user.last_visited_at).to_not be_blank + # expect(user.referrer).to_not be_blank + # expect(user.lat).to_not be_blank + # expect(user.lng).to_not be_blank + # expect(user.os).to_not be_blank + # expect(user.os_version).to_not be_blank + # expect(user.browser).to_not be_blank + # expect(user.browser_version).to_not be_blank + # expect(user.browser_language).to_not be_blank + + # visit "/tester/#{app.key}" + # expect(app.app_users.count).to be == 1 + + app.start_conversation({ + message: { + serialized_content: serialized_content + }, + from: user + }) + end + end + + describe "inbound settings" do + it "return for user user" do + user_options = [{ attribute: "email", comparison: "contains", type: "string", value: "test" }] + setting_for_user(user_segment: "some", user_options: user_options) + expect(app.query_segment("users")).to be_any + visit "/tester/#{app.key}" + expect(page).to have_css("#chaskiq-prime") + + # open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + # expect(page).to have_css("#chaskiq-prime") + # end + + # open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + # expect(page).to have_content("Start a conversation") + # end + end + + it "no return for user" do + user_options = [{ attribute: "email", comparison: "not_contains", type: "string", value: "test" }] + setting_for_user(user_segment: "some", user_options: user_options) + expect(app.query_segment("users")).to_not be_any + visit "/tester/#{app.key}" + expect(page).to_not have_css("#chaskiq-prime") + # prime_iframe = all("iframe").first + # expect(prime_iframe).to be_blank + end + + it "return for user visitor" do + visitor_options = [{ attribute: "name", comparison: "contains", type: "string", value: "isito" }] + setting_for_user(enabled: true, visitor_segment: "some", visitor_options: visitor_options) + visit "/tester/#{app.key}?sessionless=true" + + # expect(app.query_segment("visitors")).to be_any + expect(page).to have_css("#chaskiq-prime") + # prime_iframe = all("iframe").first + # Capybara.within_frame(prime_iframe) do + # expect(page).to have_css("#chaskiq-prime") + # end + end + + it "no return for visitor on some segment" do + visitor_options = [{ attribute: "email", comparison: "not_contains", type: "string", value: "test" }] + setting_for_user(visitor_segment: "some", visitor_options: visitor_options) + visit "/tester/#{app.key}?sessionless=true" + + expect(app.query_segment("visitors")).to_not be_any + expect(page).to_not have_css("#chaskiq-prime") + # prime_iframe = all("iframe").first + # expect(prime_iframe).to be_blank + end + + it "no return for visitor on disabled" do + visitor_options = [{ attribute: "email", comparison: "not_contains", type: "string", value: "test" }] + setting_for_user(visitor_segment: "some", visitors: false, visitor_options: visitor_options) + visit "/tester/#{app.key}?sessionless=true" + expect(app.query_segment("visitors")).to_not be_any + expect(page).to_not have_css("#chaskiq-prime") + # prime_iframe = all("iframe").first + # expect(prime_iframe).to be_blank + end + + it "return for visitor segment all" do + visitor_options = [] + setting_for_user(visitor_segment: "all", visitor_options: visitor_options) + visit "/tester/#{app.key}?sessionless=true" + expect(page).to have_css("#chaskiq-prime") + # open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + # expect(page).to have_css("#chaskiq-prime") + # end + end + end + + it "blocked user will not display" do + user_options = [] + setting_for_user(user_segment: "some", user_options: user_options) + expect(app.query_segment("users")).to be_any + visit "/tester/#{app.key}" + + expect(page).to have_selector("#chaskiq-prime") + + app.app_users.first.block! + visit "/tester/#{app.key}" + + expect(page).to_not have_selector("iframe") + end + + it "run previous conversations" do + app.start_conversation({ + message: { + serialized_content: serialized_content + }, + from: user + }) + + open_new_messenger({ params: { lang: "en" } }, sessionless: false) do |page| + page.click_link("See previous") + + # expect(page).to have_content(user.email) + expect(page).to have_content("a few seconds ago") + + find("#conversations-list a").click + expect(page).to have_content("foobar") + page.find("textarea").set("oeoe \n") + expect(page).to have_content("oeoe") + + app.conversations.first.add_message({ + from: app.agents.first, + message: { + html_content: "

ss

", + serialized_content: serialized_content("1111111"), + text_content: serialized_content("1111111") + } + }) + + expect(page).to have_content("1111111") + end + end + + it "start conversation" do + open_new_messenger({ params: { lang: "en" } }, sessionless: false) do |page| + page.click_link("Start a conversation") + + # expect(page).to have_content(user.email) + # expect(page).to have_content("a few seconds ago") + # + # page.find(:xpath, "/html/body/div/div/div/div[2]/div/div/div[1]/div").click + # expect(page).to have_content("foobar") + page.find("textarea").set("oeoe \n") + expect(page).to have_content("oeoe") + + app.conversations.first.add_message({ + from: app.agents.first, + message: { + html_content: "

ss

", + serialized_content: serialized_content("1111111"), + text_content: serialized_content("1111111") + } + }) + + expect(page).to have_content("1111111") + # expect(page).to have_content("test agent") + end + end + + describe "user auto messages" do + let! :message do + message = FactoryBot.create(:user_auto_message, + app: app, + segments: nil, # app.segments.first.predicates, + scheduled_at: 2.days.ago, + scheduled_to: 30.days.from_now, + serialized_content: serialized_content("First Message"), + settings: { "hidden_constraints" => ["open"] }) + + message.enable! + end + + it "receive message will track open" do + visit "/tester/#{app.key}" + + sleep(2) + + expect(all("iframe").size).to be == 1 + + # on a second visit the message will dissapear + + visit "/tester/#{app.key}" + + sleep(2) + + expect(all("iframe").size).to be == 0 + end + + it "dismiss message" do + message = FactoryBot.create(:user_auto_message, + app: app, + segments: nil, # app.segments.first.predicates, + scheduled_at: 2.days.ago, + scheduled_to: 30.days.from_now, + serialized_content: serialized_content("Second Message"), + settings: { "hidden_constraints" => ["close"] }) + + message.enable! + + visit "/tester/#{app.key}" + + Capybara.within_frame(all("iframe").first) do + expect(page).to have_content("First Message") + expect(page).to have_content("Second Message") + end + + expect(all("iframe").size).to be == 1 + + # on a second visit the message will dissapear + visit "/tester/#{app.key}" + + expect(all("iframe").size).to be == 1 + + Capybara.within_frame(all("iframe").first) do + expect(page).to_not have_content("First Message") + expect(page).to have_content("Second Message") + page.click_button("dismiss") + end + + visit "/tester/#{app.key}" + + sleep(2) + + expect(all("iframe").size).to be == 0 + end + end + + describe "tours" do + let(:host_port) do + "#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}" + end + + let(:tour) do + tour_attributes = { + "app" => app, + "key" => nil, + "from_name" => nil, + "from_email" => nil, + "reply_email" => nil, + "html_content" => nil, + "premailer" => nil, + "serialized_content" => nil, + "description" => "oli", + "sent" => nil, + "name" => "ooioij", + "scheduled_at" => 2.days.ago, + "scheduled_to" => 2.days.from_now, + "timezone" => nil, + "state" => "disabled", + "subject" => "oijoij", + "segments" => [{ "type" => "match", "value" => "and", "attribute" => "match", "comparison" => "and" }], + "type" => "Tour", + "settings" => { "url" => "/tester/#{app.key}", + "steps" => [ + { "target" => "H1", "serialized_content" => serialized_content("this is the tour") }, + { "target" => "H1", "serialized_content" => serialized_content("final tour step") } + ], + "hidden_constraints" => %w[skip finish] } + } + app.tours.create(tour_attributes) + end + + let(:tour_with_other_url) do + tour_attributes = { + "app" => app, + "key" => nil, + "from_name" => nil, + "from_email" => nil, + "reply_email" => nil, + "html_content" => nil, + "premailer" => nil, + "serialized_content" => nil, + "description" => "oli", + "sent" => nil, + "name" => "ooioij", + "scheduled_at" => 2.days.ago, + "scheduled_to" => 2.days.from_now, + "timezone" => nil, + "state" => "disabled", + "subject" => "oijoij", + "segments" => [{ "type" => "match", "value" => "and", "attribute" => "match", "comparison" => "and" }], + "type" => "Tour", + "settings" => { "url" => "#{host_port}/tester/#{app.key}/alala", + "steps" => [ + { "target" => "H1", "serialized_content" => serialized_content("this is the tour") }, + { "target" => "H1", "serialized_content" => serialized_content("final tour step") } + ], + "hidden_constraints" => %w[skip finish] } + } + app.tours.create(tour_attributes) + end + + it "display tour, track open" do + tour.enable! + visit "/tester/#{app.key}" + sleep(2) + expect(tour.metrics.where(app_user: AppUser.last, action: "open")).to be_any + end + + it "display tour, finish event" do + tour.enable! + visit "/tester/#{app.key}" + expect(page).to have_content("this is the tour") + page.find(".driver-popover-next-btn").click + expect(page).to have_content("final tour step") + page.click_button("Done") + expect(page).not_to have_content("final tour step") + visit "/tester/#{app.key}" + expect(page).not_to have_content("this is the tour") + end + + it "display tour, skip event" do + tour.enable! + visit "/tester/#{app.key}" + + expect(page).to have_content("this is the tour") + + page.find(".driver-popover-close-btn").click + + expect(page).not_to have_content("final tour step") + + visit "/tester/#{app.key}" + + expect(page).not_to have_content("this is the tour") + end + + it "display on configured url" do + tour.enable! + visit "/tester/#{app.key}/another" + sleep(5) + expect(page).to_not have_content("this is the tour") + + visit "/tester/#{app.key}" + sleep(5) + expect(page).to have_content("this is the tour") + end + end + + describe "availability" do + before :each do + end + + it "next week" do + app.update(timezone: "UTC", team_schedule: [ + { day: "tue", from: "01:00", to: "01:30" } + ]) + + open_new_messenger({ params: { lang: "es" } }, sessionless: true) do |page| + expect(page).to have_content("volvemos la proxima semana") + end + end + end + + describe "bot default settings" do + context "sessionless" do + it "shows reply time" do + # Sidekiq::Testing.inline! do + + app.update( + timezone: "UTC", + lead_tasks_settings: { + delay: false, + routing: "assign", + email_requirement: "email_only", + assignee: agent_role.agent, + share_typical_time: true + }, + team_schedule: [ + { day: "tue", from: "01:00", to: "01:30" } + ] + ) + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + page.click_link("Start a conversation") + page.find("textarea").set("oeoe \n") + expect(page).to have_content("oeoe") + expect(page).to have_content("will reply as soon as they can.") + end + + # end + end + + it "shows email requirement" do + Sidekiq::Testing.inline! + + app.update( + timezone: "UTC", + lead_tasks_settings: { + delay: false, + routing: "assign", + email_requirement: "email_only", + assignee: agent_role.agent.id, + share_typical_time: true + }, + email_requirement: "Always", + team_schedule: [ + { day: "tue", from: "01:00", to: "01:30" } + ] + ) + + # Add the 'Qualifier' package or similar setup + add_app_package("Qualifier") + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + page.click_link("Start a conversation") + page.find("textarea").set("oeoe \n") + expect(page).to have_content("oeoe") + + expect(page).to have_content("Are you an existing my app customer?") + + page.click_button("Yes, I'm a customer") + expect(page).to have_content("GET NOTIFIED BY EMAIL") + fill_in("email", with: "John@apple.cl") + page.find("button#email").click + + expect(page).to have_content("Thank you") + end + end + + it "not shows email requirement" do + Sidekiq::Testing.inline! + + app.update( + timezone: "UTC", + lead_tasks_settings: { + delay: false, + routing: "assign", + email_requirement: "email_only", + assignee: agent_role.agent, + share_typical_time: true + }, + email_requirement: "never", + team_schedule: [ + { day: "tue", from: "01:00", to: "01:30" } + ] + ) + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do |page| + page.click_link("Start a conversation") + expect(page).to_not have_content("enter your email") + end + end + end + end +end diff --git a/spec/system/messenger/translations_spec.rb b/spec/system/messenger/translations_spec.rb new file mode 100644 index 000000000..2be02afb1 --- /dev/null +++ b/spec/system/messenger/translations_spec.rb @@ -0,0 +1,103 @@ +require "rails_helper" + +RSpec.describe "Translations Spec", type: :system, js: true do + let!(:app) do + Plugin.restore_plugins_from_fs + + FactoryBot.create(:app, encryption_key: "unodostrescuatro", + active_messenger: "true", + state: "enabled", + domain_url: "*") + end + + let!(:agent) do + agent = app.add_agent({ + email: "test@test.cl", + name: "sharleena", + password: "123456", + password_confirmation: "123456" + }, + role_attrs: { + role: "admin" + }) + agent.agent + end + + def translations + app.update({ + greetings_es: "Hola amigo", + greetings_en: "hello friend", + + intro_en: "we are here to help", + intro_es: "somos un equipo genial", + + tagline_es: "estamos aqui para ayudarte", + tagline_en: "we are an awesome team" + }) + end + + before :each do + translations + end + + it "user lang en" do + open_new_messenger({ params: { lang: "en" } }) do |page| + expect(page).to have_content("Start a conversation") + expect(page).to have_content("hello friend") + expect(page).to have_content("we are here to help") + + # Verifying app user properties + expect(app.app_users.size).to eq(1) + expect(app.app_users.last.lang).to eq("en") + end + end + + it "user lang es" do + open_new_messenger({ params: { lang: "es" } }) do + expect(page).to have_content("Inicia una conversaci\u00F3n") + expect(app.app_users.size).to eq(1) + expect(app.app_users.last.lang).to eq("es") + expect(app.app_users.last.name).to eq("miguel") + end + end + + it "visitor lang en" do + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do + expect(page).to have_content("Start a conversation") + expect(page).to have_content("hello friend") + expect(app.app_users.size).to eq(1) + end + end + + it "visitor lang es property" do + open_new_messenger({ params: { lang: "es" } }, sessionless: true) do + expect(page).to have_content("Inicia una conversaci\u00F3n") + expect(page).to have_content("Hola") + expect(app.app_users.size).to eq(1) + expect(Visitor.last.lang).to eq("es") + end + end + + it "lang en start conversation" do + # app.add_user(email: "test@test.cl") + + # start_conversation_from_agent + + open_new_messenger({ params: { lang: "en" } }, sessionless: true) do + expect(page).to have_content("Start a conversation") + expect(page).to have_content("hello") + expect(app.app_users.size).to eq(1) + + start_conversation_from_agent + + sleep(2) + # expect(Visitor.last.lang).to eq('en') + # click_link("See previous") + + # sleep(2) + expect(page).to have_content("foobar") + end + end + + # Additional test cases... +end diff --git a/spec/system/messenger/user_auto_messages_spec.rb b/spec/system/messenger/user_auto_messages_spec.rb new file mode 100644 index 000000000..464090415 --- /dev/null +++ b/spec/system/messenger/user_auto_messages_spec.rb @@ -0,0 +1 @@ +# TODO