diff --git a/.travis.yml b/.travis.yml index f5433b03d..d8fd4edc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,13 @@ language: ruby -#addons: -# chrome: stable addons: + postgresql: 11 + chrome: stable apt: packages: # Ubuntu 16+ does not install this dependency by default, so we need to install it ourselves - libgconf-2-4 + - postgresql-11 + - postgresql-client-11 services: - postgresql @@ -13,15 +15,20 @@ services: env: global: - NODE_ENV=test + - PGPORT=5433 cache: bundler: true - directories: - - node_modules + npm: true yarn: true + directories: + - node_modules + - ~/.cache before_install: - gem update --system - gem install bundler -v 1.17.3 - nvm install 10.13.0 +#- google-chrome-beta --headless --disable-gpu --remote-debugging-port=9222 http://localhost & + before_script: - cp config/database.yml.travis config/database.yml - cp ./config/webpacker.ci.yml ./config/webpacker.yml diff --git a/Gemfile b/Gemfile index 6d09d0197..f565a5a96 100644 --- a/Gemfile +++ b/Gemfile @@ -147,7 +147,8 @@ group :test do gem lib # , :git => "https://github.com/rspec/#{lib}.git", :branch => 'master' end gem 'brakeman' - gem 'database_cleaner' + gem 'database_cleaner-active_record' + gem 'database_cleaner-redis' gem 'factory_bot_rails' gem 'rubocop', '~> 0.76.0', require: false gem 'rubocop-performance', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 657ddabda..52acf16df 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,7 +123,7 @@ GEM xml-simple aws-sigv4 (1.2.1) aws-eventstream (~> 1, >= 1.0.2) - batch-loader (1.4.1) + batch-loader (1.5.0) bcrypt (3.1.13) bindex (0.8.1) biz (1.8.2) @@ -169,9 +169,15 @@ GEM crass (1.0.6) css_parser (1.7.0) addressable - cypress-on-rails (1.6.0) + cypress-on-rails (1.7.0) rack - database_cleaner (1.7.0) + database_cleaner (1.8.5) + database_cleaner-active_record (1.8.0) + activerecord + database_cleaner (~> 1.8.0) + database_cleaner-redis (1.8.0) + database_cleaner (~> 1.8.0) + redis deep_cloneable (3.0.0) activerecord (>= 3.1.0, < 7) devise (4.7.1) @@ -555,7 +561,8 @@ DEPENDENCIES capistrano3-puma chronic (~> 0.10.2) cypress-on-rails (~> 1.0) - database_cleaner + database_cleaner-active_record + database_cleaner-redis deep_cloneable devise (= 4.7.1) devise_invitable (~> 2.0) diff --git a/app/graphql/types/conversation_part_type.rb b/app/graphql/types/conversation_part_type.rb index 28dd74501..d48483654 100644 --- a/app/graphql/types/conversation_part_type.rb +++ b/app/graphql/types/conversation_part_type.rb @@ -39,12 +39,15 @@ def app_user end def message + # object.messageable id = object.messageable_id key = object.messageable_type BatchLoader::GraphQL.for(id).batch(key: key) do |ids, loader, args| model = Object.const_get(args[:key]) - model.where(id: ids).each { |record| loader.call(record.id, record) } + model.where(id: ids).each { |record| + loader.call(record.id, record) + } end end end diff --git a/app/javascript/src/pages/bots/settings.js b/app/javascript/src/pages/bots/settings.js index 5000f027f..18b4c9343 100644 --- a/app/javascript/src/pages/bots/settings.js +++ b/app/javascript/src/pages/bots/settings.js @@ -7,10 +7,16 @@ import ContentHeader from '../../components/PageHeader' import Content from '../../components/Content' import Input from '../../components/forms/Input' import graphql from '../../graphql/client' +import defaultFields from '../../shared/defaultFields' + +import { InlineFilterDialog } from '../../components/segmentManager' +import SegmentItemButton from '../../components/segmentManager/itemButton' + import { AGENTS, BOT_TASKS } from '../../graphql/queries' import { updateApp } from '../../actions/app' import { setCurrentPage } from '../../actions/navigation' +import {PlusIcon, DeleteIcon} from '../../components/icons' import I18n from '../../shared/FakeI18n' const SettingsForm = ({ app, data, errors, dispatch }) => { @@ -135,9 +141,11 @@ function UsersSettings ({ updateData({ users: state }) }, [state]) + /* useEffect(() => { if (!state.override_with_task) setState({ ...state, trigger: null }) }, [state.override_with_task]) + */ const handleChange = (name) => (event) => { setState({ ...state, [name]: event.target.checked }) @@ -156,7 +164,7 @@ function UsersSettings ({

- {I18n.t("task_bots.settings.users.start_conversation")} + {I18n.t('task_bots.settings.users.start_conversation')}

- +
} @@ -192,7 +201,7 @@ function UsersSettings ({
@@ -215,9 +224,11 @@ function LeadsSettings ({ updateData({ leads: state }) }, [state]) + /* useEffect(() => { if (!state.override_with_task) setState({ ...state, trigger: null }) }, [state.override_with_task]) + */ const handleChange = (name) => (event) => { setValue(name, event.target.checked) @@ -241,16 +252,16 @@ function LeadsSettings ({

- {I18n.t("task_bots.settings.leads.start_conversation")} + {I18n.t('task_bots.settings.leads.start_conversation')}

-
+
- +
} +

@@ -301,10 +314,10 @@ function LeadsSettings ({ @@ -324,8 +337,8 @@ function LeadsSettings ({ name="routing" type="radio" value="close" - defaultChecked={state.routing === "close"} - //value={state.routing} + defaultChecked={state.routing === 'close'} + // value={state.routing} onChange={handleRadioChange} label={I18n.t('task_bots.settings.leads.close')} /> @@ -352,7 +365,7 @@ function LeadsSettings ({ { getTasks() }, []) + useEffect(()=> { + setValue('tasks_rules', items) + }, [JSON.stringify(items)]) + + function addItem (item) { + setItems(items.concat(item)) + } + + function updateItem (name, item, i) { + setItems(items.map((o, index) => index !== i + ? o : { ...o, [name]: item } + ) + ) + } + + function addEmptyItem () { + addItem({}) + } + + function deleteItem (i) { + setItems(items.filter((item, index) => index !== i)) + } + + return ( +
+ { + items.map((o, i) => ( + + )) + } + + + +
+ ) +} + +function TaskSelector ({ + app, + tasks, + item, + index, + value, + deleteRule, + updateRule +}) { + + const [selected, setSelected] = React.useState(item.trigger) + useEffect(() => { - setValue('trigger', selected) + // setValue(selected, index) + updateRule('trigger', selected, index) }, [selected]) function handleChange (e) { setSelected(e.value) } - const selectedAgent = tasks.find((o) => o.id === selected) + const selectedTask = tasks.find((o) => o.id === selected) let defaultValue = null - if (selectedAgent) { - defaultValue = { label: selectedAgent.title, value: selectedAgent.id } + if (selectedTask) { + defaultValue = { label: selectedTask.title, value: selectedTask.id } } - const options = [{label: 'none', value: null}].concat( + const options = [{ label: 'none', value: null }].concat( tasks.map((o) => ({ label: o.title, value: o.id })) ) return ( -
- +
+ +
+ +
+ updateRule('predicates', item, index) } + /> + +
+ +
+
+ + +
) } +function RuleSelector ({ app, update, data }) { + const [predicates, setPredicates] = React.useState(data) + + React.useEffect(() => { + update(predicates) + }, [predicates]) + + function updatePredicates (data) { + setPredicates(data) + } + + function deletePredicate (data) { + setPredicates(data) + } + + function addPredicate (data) { + const pendingPredicate = { + attribute: data.name, + comparison: null, + type: data.type, + value: data.value + } + setPredicates(predicates.concat(pendingPredicate)) + } + + function displayName (o) { + return o.attribute.split('_').join(' ') + } + + function getTextForPredicate (o) { + if (o.type === 'match') { + return `Match ${o.value === 'and' ? 'all' : 'any'} criteria` + } else { + return `${displayName(o)} ${o.comparison ? o.comparison : ''} ${ + o.value ? o.value : '' + }` + } + } + + return
+ { + predicates.map((o, i) => { + return
+ { + // debugger + // }} + deletePredicate={(items) => { + deletePredicate(items) + }} + /> + +
+ }) + } + + { + addPredicate(predicate) + }} + /> +
+} + export default SettingsForm diff --git a/app/models/app_user.rb b/app/models/app_user.rb index 99fc1152c..f2896d98a 100644 --- a/app/models/app_user.rb +++ b/app/models/app_user.rb @@ -266,16 +266,15 @@ def register_visit(options) end def register_in_crm - # refactor this query - app.app_packages - .joins(:app_package_integrations) - .tagged_with("crm").each do |pkg| - pkg.app_package_integrations.each do |integration| - profile = self.external_profiles.find_or_create_by( - provider: pkg.name.downcase - ) - profile.sync - end + crm_tags = app.app_packages.tagged_with("crm").pluck(:id) + integrations = app.app_package_integrations.includes(:app_package) + .where(app_package: crm_tags) + + integrations.each do |integration| + profile = self.external_profiles.find_or_create_by( + provider: pkg.name.downcase + ) + profile.sync end end diff --git a/app/services/action_trigger_factory.rb b/app/services/action_trigger_factory.rb index 9fff78aae..9f6d30fe3 100644 --- a/app/services/action_trigger_factory.rb +++ b/app/services/action_trigger_factory.rb @@ -287,17 +287,30 @@ def self.infer_for(app:, user:) subject end - def self.find_configured_bot_for_user(app: , user:) - if user.is_a?(Lead) - id = app.lead_tasks_settings['trigger'] - return if id.blank? - return app.bot_tasks.find(id) - elsif(user.is_a?(AppUser)) - id = app.user_tasks_settings['trigger'] - return if id.blank? - return app.bot_tasks.find(id) - end - nil + def self.find_configured_bot_for_user(app:, user:) + settings_namespace = user.is_a?(Lead) ? :lead_tasks_settings : :user_tasks_settings + + return if !app.send(settings_namespace)['override_with_task'] + return if app.send(settings_namespace)['task_rules'].empty? + + return find_by_segment( + app: app, + user: user, + rules: app.send(settings_namespace)['task_rules'] + ) + end + + def self.find_by_segment(app: , user:, rules:) + rules.find{|o| + comparator = SegmentComparator.new( + user: user, + predicates: o['predicates'] || [] + ) + if comparator.compare && trigger = app.bot_tasks.find(o['trigger']) + return trigger + end + nil + } end diff --git a/config/application.rb b/config/application.rb index f3ee939b5..e8c278c57 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,6 +40,8 @@ class Application < Rails::Application end end + config.middleware.use BatchLoader::Middleware + URLcrypt::key = [ENV['SECRET_KEY_BASE']].pack('H*') locales = %w[af sq ar eu bg be ca hr cs da nl en eo et fo fi fr gl de el iw hu is ga it ja ko lv lt mk mt no pl pt ro ru gd sr sr sk sl es sv tr uk] diff --git a/config/environments/test.rb b/config/environments/test.rb index 4f6017ed2..a08888993 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -7,7 +7,7 @@ # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! - config.cache_classes = ENV['CI'].present? + config.cache_classes = false #ENV['CI'].present? ENV['HOST'] = 'http://localhost:5002' ENV['WS'] = 'ws://localhost:5002' diff --git a/config/puma.rb b/config/puma.rb index ff86cf58f..b07081824 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -33,5 +33,9 @@ # # preload_app! +on_worker_boot do + ActiveRecord::Base.establish_connection if defined?(ActiveRecord) +end + # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart diff --git a/cypress.json b/cypress.json index 18d99a4c1..1d7f4be6c 100644 --- a/cypress.json +++ b/cypress.json @@ -4,7 +4,7 @@ "baseUrl": "http://localhost:5002", "blacklistHosts": null, "chromeWebSecurity": true, - "defaultCommandTimeout": 30000, + "defaultCommandTimeout": 10000, "env": {}, "execTimeout": 60000, "fileServerFolder": "", diff --git a/package.json b/package.json index e4c54f7ff..a23f6dc56 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "rails-cy": "bundle exec rails server -e test -p 5002", "cypress:open": "./node_modules/.bin/cypress open", "cypress:run": "./node_modules/.bin/cypress run", - "cypress:ci": "./node_modules/.bin/cypress run --headless --browser chrome --record --key 0998a03f-f6fe-4acf-8444-b81533c950cd", + "cypress:ci": "./node_modules/.bin/cypress run --headless --browser chrome --record --key 0998a03f-f6fe-4acf-8444-b81533c950cd --parallel --ci-build-id $TRAVIS_BUILD_ID", "dev": "./bin/webpack-dev-server", "build": "bundle exec rake assets:precompile" } diff --git a/spec/cypress/app_commands/clean.rb b/spec/cypress/app_commands/clean.rb index a0c945fcf..c46d731f2 100644 --- a/spec/cypress/app_commands/clean.rb +++ b/spec/cypress/app_commands/clean.rb @@ -1,24 +1,16 @@ # frozen_string_literal: true -ActiveRecord::Base.connection_pool.with_connection do +#require 'database_cleaner/active_record' +#require 'database_cleaner/redis' - if defined?(DatabaseCleaner) - # cleaning the database using database_cleaner - DatabaseCleaner.strategy = :truncation - DatabaseCleaner.clean - DatabaseCleaner.strategy = :truncation - DatabaseCleaner.clean - # see https://github.com/bmabey/database_cleaner/issues/99 - #begin - # ActiveRecord::Base.connection.send :rollback_transaction_records, true - #rescue - #end - else - logger.warn 'add database_cleaner or update clean_db' - #Post.delete_all if defined?(Post) - end +DatabaseCleaner.strategy = :truncation - Rails.logger.info 'APPCLEANED' # used by log_fail.rb - # code +#DatabaseCleaner[:redis].strategy = :truncation, { only: ["test:*"] } +# then, whenever you need to clean the DB +begin + DatabaseCleaner.clean +rescue => e + sleep 2 + DatabaseCleaner.clean_with :deletion end \ No newline at end of file diff --git a/spec/cypress/app_commands/start_conversation.rb b/spec/cypress/app_commands/start_conversation_command.rb similarity index 100% rename from spec/cypress/app_commands/start_conversation.rb rename to spec/cypress/app_commands/start_conversation_command.rb diff --git a/spec/cypress/integration/messenger/conversations_spec.js b/spec/cypress/integration/messenger/conversations_spec.js index 84ae3c349..68246f9ce 100644 --- a/spec/cypress/integration/messenger/conversations_spec.js +++ b/spec/cypress/integration/messenger/conversations_spec.js @@ -1,11 +1,10 @@ describe('Conversation Spec', function () { + describe('run previous', function () { - beforeEach(() => { + it('run previous conversations', function () { cy.appScenario('start_conversation_from_agent') - }) - it('run previous conversations', function () { openMessenger(($body) => { expect($body.html()).to.contain('Start a conversation') cy.appEval('App.last.app_users.size').then((res) => { @@ -29,11 +28,8 @@ describe('Conversation Spec', function () { }) describe('basic', function () { - beforeEach(() => { - cy.appScenario('basic') - }) - it('start_conversation', function () { + cy.appScenario('basic') openMessenger(($body, appKey) => { expect($body.html()).to.contain('Start a conversation') @@ -50,7 +46,7 @@ describe('Conversation Spec', function () { .type('oeoe \n').then(() => { cy.wrap($body).contains('oeoe') - cy.app('start_conversation', { text: '11111', app_key: appKey, rules: [] }) + cy.app('start_conversation_command', { text: '11111', app_key: appKey, rules: [] }) cy.wrap($body).contains('was assigned to this conversation') cy.wrap($body).contains('11111') diff --git a/spec/cypress/integration/messenger/task_bot_spec.js b/spec/cypress/integration/messenger/task_bot_spec.js index 10963c3f6..01b868797 100644 --- a/spec/cypress/integration/messenger/task_bot_spec.js +++ b/spec/cypress/integration/messenger/task_bot_spec.js @@ -130,7 +130,7 @@ describe('Task bot Spec', function () { cy.wrap($body).contains('will reply as soon as they can.') - // cy.wrap($body).contains('oeoe') + cy.wrap($body).contains('oeoe') cy.wrap($body).contains('Are you an existing') cy.wrap($body).contains("I'm a customer").click() cy.wrap($body).contains("You replied Yes, I'm a customer") @@ -171,8 +171,9 @@ describe('Task bot Spec', function () { cy.wrap($body) .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .type('oeoe \n') - cy.wrap($body).contains('four') + .type('oeoe \n').then(()=> { + cy.wrap($body).contains('four') + }) }) }) }) @@ -189,37 +190,94 @@ describe('Task bot Spec', function () { cy.appEval('Redis.current.del("app_user:1:trigger_locked")') }) - it('sessionless enter bot on new conversation', function () { + it('sessionless enter bot on new conversation with predicates', function () { cy.appEval('App.last').then((results) => { const appKey = results.key - cy.appEval(`App.find_by(key: '${appKey}').update(lead_tasks_settings: {trigger: 1} )`) - - cy.app('bot_task_command', { - app_key: appKey - }).then((res) => { - cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) - - cy.log(res) + cy.appEval(`App.find_by(key: '${appKey}').update(lead_tasks_settings: { + override_with_task: true, + task_rules: [ + { trigger: 1, + predicates: [ + { + "attribute": "lang", + "comparison": "eq", + "type": "string", + "value": "en" + }] + } + ] + })`).then(()=>{ + cy.app('bot_task_command', { + app_key: appKey + }).then((res) => { + cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) + + cy.log(res) + + helpers.openMessenger('?sessionless=true&lang=en', ($body, appKey) => { + expect($body.html()).to.contain('Start a conversation') + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') + .click() + .then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .should('be.enabled').then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .type('oeoe \n').then(() => { + cy.wrap($body).contains('oeoe') + cy.wrap($body).contains('one') + cy.wrap($body).contains('two') + cy.wrap($body).contains('tree') + }) + }) + }) + }) + }) + }) - helpers.openMessenger('?sessionless=true', ($body, appKey) => { - expect($body.html()).to.contain('Start a conversation') - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') - .click() - .then(() => { - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .should('be.enabled').then(() => { - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .type('oeoe \n').then(() => { - cy.wrap($body).contains('oeoe') - cy.wrap($body).contains('one') - cy.wrap($body).contains('two') - cy.wrap($body).contains('tree') - }) - }) - }) + }) + }) + + it('sessionless enter bot on new conversation with empty predicates', function () { + cy.appEval('App.last').then((results) => { + const appKey = results.key + cy.appEval(`App.find_by(key: '${appKey}').update(lead_tasks_settings: { + override_with_task: true, + task_rules: [ + { trigger: 1, + predicates: [] + } + ] + })`).then(() => { + cy.app('bot_task_command', { + app_key: appKey + }).then((res) => { + cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) + + cy.log(res) + + helpers.openMessenger('?sessionless=true&lang=en', ($body, appKey) => { + expect($body.html()).to.contain('Start a conversation') + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') + .click() + .then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .should('be.enabled').then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .type('oeoe \n').then(() => { + cy.wrap($body).contains('oeoe') + cy.wrap($body).contains('one') + cy.wrap($body).contains('two') + cy.wrap($body).contains('tree') + }) + }) + }) + }) }) }) }) @@ -227,9 +285,7 @@ describe('Task bot Spec', function () { it('sessionless default bot new conversation', function () { cy.appEval('App.last').then((results) => { - const appKey = results.key - //cy.appEval(`App.find_by(key: '${appKey}').update(lead_tasks_settings: {trigger: 1} )`) - + const appKey = results.key cy.app('bot_task_command', { app_key: appKey }).then((res) => { @@ -262,35 +318,55 @@ describe('Task bot Spec', function () { it('user session default bot new conversation', function () { cy.appEval('App.last').then((results) => { const appKey = results.key - cy.appEval(`App.find_by(key: '${appKey}').update(user_tasks_settings: {trigger: 1} )`) - - cy.app('bot_task_command', { - app_key: appKey - }).then((res) => { - cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) - cy.log(res) - - helpers.openMessenger('', ($body, appKey) => { - expect($body.html()).to.contain('Start a conversation') - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') - .click() - .then(() => { - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .should('be.enabled').then(() => { - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .type('oeoe \n').then(() => { - cy.wrap($body).contains('oeoe') - - cy.wrap($body).contains('one') - cy.wrap($body).contains('two') - cy.wrap($body).contains('tree') - }) - }) - }) + cy.appEval(`App.find_by(key: '${appKey}').update(user_tasks_settings: { + override_with_task: true, + task_rules: [ + { trigger: 1, + predicates: [ + { + "attribute": "lang", + "comparison": "eq", + "type": "string", + "value": "en" + }, + { + "attribute": "num_devices", + "comparison": "eq", + "type": "integer", + "value": 2 + }] + } + ] + })`).then(() => { + cy.app('bot_task_command', { + app_key: appKey + }).then((res) => { + cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) + + cy.log(res) + + helpers.openMessenger('', ($body, appKey) => { + expect($body.html()).to.contain('Start a conversation') + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') + .click() + .then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .should('be.enabled').then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .type('oeoe \n').then(() => { + cy.wrap($body).contains('oeoe') + + cy.wrap($body).contains('one') + cy.wrap($body).contains('two') + cy.wrap($body).contains('tree') + }) + }) + }) + }) }) }) }) @@ -299,35 +375,49 @@ describe('Task bot Spec', function () { it('user session default bot new conversation', function () { cy.appEval('App.last').then((results) => { const appKey = results.key - cy.appEval(`App.find_by(key: '${appKey}').update(user_tasks_settings: {trigger: 1} )`) - - cy.app('bot_task_command', { - app_key: appKey - }).then((res) => { - cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) - cy.log(res) - - helpers.openMessenger('', ($body, appKey) => { - expect($body.html()).to.contain('Start a conversation') - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') - .click() - .then(() => { - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .should('be.enabled').then(() => { - cy.wrap($body) - .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') - .type('oeoe \n').then(() => { - cy.wrap($body).contains('oeoe') - - cy.wrap($body).contains('one') - cy.wrap($body).contains('two') - cy.wrap($body).contains('tree') - }) - }) - }) + cy.appEval(`App.find_by(key: '${appKey}').update(user_tasks_settings: { + override_with_task: true, + task_rules: [ + { trigger: 1, + predicates: [ + { + "attribute": "lang", + "comparison": "eq", + "type": "string", + "value": "en" + }] + } + ] + })`).then(() => { + cy.app('bot_task_command', { + app_key: appKey + }).then((res) => { + cy.appEval(`BotTask.find(${res.id}).update(state: 'disabled' )`) + + cy.log(res) + + helpers.openMessenger('', ($body, appKey) => { + expect($body.html()).to.contain('Start a conversation') + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div[1]/div/div/div[2]/a[1]') + .click() + .then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .should('be.enabled').then(() => { + cy.wrap($body) + .xpath('/html/body/div/div/div/div[2]/div/div/div/div[2]/div/div/textarea') + .type('oeoe \n').then(() => { + cy.wrap($body).contains('oeoe') + + cy.wrap($body).contains('one') + cy.wrap($body).contains('two') + cy.wrap($body).contains('tree') + }) + }) + }) + }) }) }) }) diff --git a/spec/cypress/screenshots/messenger/conversations_spec.js/Conversation Spec -- basic -- start_conversation (failed).png b/spec/cypress/screenshots/messenger/conversations_spec.js/Conversation Spec -- basic -- start_conversation (failed).png new file mode 100644 index 000000000..882bb9b88 Binary files /dev/null and b/spec/cypress/screenshots/messenger/conversations_spec.js/Conversation Spec -- basic -- start_conversation (failed).png differ diff --git a/spec/cypress/support/on-rails.js b/spec/cypress/support/on-rails.js index ec3929bad..787a2ed70 100644 --- a/spec/cypress/support/on-rails.js +++ b/spec/cypress/support/on-rails.js @@ -45,7 +45,13 @@ Cypress.on('fail', (err, runnable) => { // allow app to generate additional logging data Cypress.$.ajax({ url: '/__cypress__/command', - data: JSON.stringify({name: 'log_fail', options: {error_message: err.message, runnable_full_title: runnable.fullTitle() }}), + data: JSON.stringify({ + name: 'log_fail', + options: { + error_message: err.message, + runnable_full_title: runnable.fullTitle() + } + }), async: false, method: 'POST' });