jam-cloud/web/spec/support/utilities.rb

1089 lines
35 KiB
Ruby

require Rails.root.join('app/helpers/application_helper.rb')
include ApplicationHelper
# add a hover_intent method to element, so that you can do find(selector).hover_intent
module Capybara
module Node
class Element
def attempt_hover
begin
hover
rescue => e
end
end
def hover_intent
hover
sleep 0.3
attempt_hover
sleep 0.3
attempt_hover
end
def help_bubble
hover_intent
end
end
end
end
# holds a single test's session name's, mapped to pooled session names
$capybara_session_mapper = {}
# called in before (or after) test, to make sure each test run has it's own map of session names
def reset_session_mapper
$capybara_session_mapper.clear
Capybara.session_name = :default
end
# manages the mapped session name
def mapped_session_name(session_name)
return :default if session_name == :default # special treatment for the built-in session
$capybara_session_mapper[session_name] ||= 'session_' + $capybara_session_mapper.length.to_s
end
# in place of ever using Capybara.session_name directly,
# this utility is used to handle the mapping of session names in a way across all tests runs
def in_client(name, &blk)
session_name = name.class == JamRuby::User ? name.id : name
#Capybara.session_name = mapped_session_name(session_name)
Capybara.using_session(session_name, &blk)
end
def cookie_jar
Capybara.current_session.driver.browser.current_session.instance_variable_get(:@rack_mock_session).cookie_jar
end
#see also ruby/spec/support/utilities.rb
JAMKAZAM_TESTING_BUCKET = 'jamkazam-testing' #at least, this is the name given in jam-ruby
def wipe_s3_test_bucket
s3 = AWS::S3.new(:access_key_id => Rails.application.config.aws_access_key_id,
:secret_access_key => Rails.application.config.aws_secret_access_key)
test_bucket = s3.buckets[JAMKAZAM_TESTING_BUCKET]
if test_bucket.name == JAMKAZAM_TESTING_BUCKET
test_bucket.objects.each do |obj|
obj.delete
end
end
end
def authorize_google_user(youtube_client, user, google_password)
youtube_client.wait_for_callback(2112) do |access_token|
#puts("Authorizing with token #{access_token}")
user_auth_hash = {
:provider => "google_login",
:uid => user.email,
:token => access_token,
:token_expiration => nil,
:secret => ""
}
authorization = user.user_authorizations.build(user_auth_hash)
authorization.save
end
url = youtube_client.get_login_url(user.email)
#puts("Login URL: #{url}")
visit url
sleep(1)
# (the username is filled in with a hint in URL):
# fill_in "Usernm", with: user.email
find('#next').trigger(:click)
sleep(5)
# Fill in password
fill_in "Passwd", with: google_password
find('#signIn').trigger(:click)
# Wait for submit to enable and then click it:
sleep(5)
save_screenshot("about_to_submit.png")
find('#submit_approve_access').trigger(:click)
sleep(5)
youtube_client
end
def sign_in(user)
visit signin_path
within('#landing-inner form.signin-form') do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "SIGN IN"
end
# Sign in when not using Capybara as well.
cookie_jar[:remember_token] = user.remember_token
end
def set_cookie(k, v)
case Capybara.current_session.driver
when Capybara::Cuprite::Driver
page.driver.set_cookie(k,v)
when Capybara::RackTest::Driver
headers = {}
Rack::Utils.set_cookie_header!(headers,k,v)
cookie_string = headers['Set-Cookie']
Capybara.current_session.driver.browser.set_cookie(cookie_string)
when Capybara::Selenium::Driver
page.driver.browser.manage.add_cookie(:name=>k, :value=>v)
else
raise "no cookie-setter implemented for driver #{Capybara.current_session.driver.class.name}"
end
end
# def sign_in_poltergeist(user, options = {})
# validate = options[:validate]
# validate = true if validate.nil?
# if user.password.nil? && !options[:password]
# raise "user has no password. Use a user newly created so that it's password is still present"
# end
# uri = URI.parse(current_url)
# # in tests, we often have an issue where an old signin screen is unloading
# # as this one is loading.
# # so one way to fix this is to go to a different page in this case, and then come back to /signin
# if uri.path == signin_path
# visit '/'
# should_be_at_root
# end
# visit signin_path
# page.should have_selector('#landing-inner form.signin-form')
# within('#landing-inner form.signin-form') do
# fill_in "Email Address:", with: user.email
# fill_in "Password:", with: options[:password] || user.password
# click_button "SIGN IN"
# end
# page.should have_no_selector('h1', text: 'sign in or register')
# wait_until_curtain_gone
# # presence of this means websocket gateway is not working
# page.should have_no_selector('.no-websocket-connection') if validate
#end
def sign_in_poltergeist(user, options = {})
validate = options[:validate]
validate = true if validate.nil?
if user.password.nil? && !options[:password]
raise "user has no password. Use a user newly created so that it's password is still present"
end
uri = URI.parse(current_url)
# in tests, we often have an issue where an old signin screen is unloading
# as this one is loading.
# so one way to fix this is to go to a different page in this case, and then come back to /signin
if uri.path == signin_path
visit '/'
should_be_at_root
end
visit signin_path
page.should have_selector('#landing-inner form.signin-form')
within('#landing-inner form.signin-form') do
fill_in "Email Address:", with: user.email
fill_in "Password:", with: options[:password] || user.password
click_button "SIGN IN"
end
page.should have_no_selector('h1', text: 'sign in or register')
wait_until_curtain_gone
if validate
wait_for_jam_server_connected
# presence of this means websocket gateway is not working
page.should have_no_selector('.no-websocket-connection')
end
end
def jam_server_state
page.evaluate_script(<<~JS)
(function() {
var jq = window.jQuery;
var s = (window.JK && window.JK.JamServer) || {};
return {
present: !!(window.JK && window.JK.JamServer),
currentUserId: (window.JK && window.JK.currentUserId) || null,
gonUserId: (window.gon && window.gon.user_id) || null,
jamClientPresent: !!window.jamClient,
jamClientHasGetOperatingMode: !!(window.jamClient && window.jamClient.getOperatingMode),
connected: !!s.connected,
connecting: !!s.connecting,
reconnecting: !!s.reconnecting,
signedIn: !!s.signedIn,
noReconnect: !!s.noReconnect,
socketReadyState: (s.socket && typeof s.socket.readyState !== 'undefined') ? s.socket.readyState : null,
rememberTokenPresent: !!(jq && jq.cookie && jq.cookie('remember_token'))
};
})();
JS
rescue StandardError => e
{ error: e.message }
end
def wait_for_jam_server_connected(timeout: Capybara.default_max_wait_time)
deadline = Time.now + timeout
last_state = nil
last_nudge_at = Time.at(0)
until Time.now > deadline
last_state = jam_server_state
if (last_state[:currentUserId] || last_state['currentUserId']) &&
!(last_state[:connected] || last_state['connected']) &&
!(last_state[:connecting] || last_state['connecting']) &&
Time.now - last_nudge_at > 1
page.execute_script(<<~JS)
(function() {
if (!(window.JK && window.JK.JamServer && window.JK.currentUserId)) return;
if (window.JK.JamServer.connected || window.JK.JamServer.connecting) return;
try { window.JK.JamServer.connect(); } catch (e) {}
})();
JS
last_nudge_at = Time.now
end
return true if last_state[:connected] || last_state['connected']
sleep 0.1
end
debug_console = begin
driver = page.driver
browser = driver.respond_to?(:browser) ? driver.browser : nil
if browser && browser.respond_to?(:console_messages)
browser.console_messages.map { |m| m.respond_to?(:text) ? m.text : m.to_s }.last(10)
else
[]
end
rescue StandardError => e
["console read error: #{e.message}"]
end
raise "JamServer did not connect within #{timeout}s. state=#{last_state.inspect} console=#{debug_console.inspect}"
end
def wait_for_client_layout_ready(timeout: Capybara.default_max_wait_time)
deadline = Time.now + timeout
until Time.now > deadline
ready = page.evaluate_script("!!(window.JK && window.JK.app && window.JK.app.layout && window.JK.app.layout.bindDialog)")
return true if ready
sleep 0.1
end
raise "Client layout not ready within #{timeout}s"
end
def ensure_client_post_connect_init(timeout: Capybara.default_max_wait_time)
wait_for_client_layout_ready(timeout: timeout)
result = page.evaluate_script(<<~JS)
(function() {
if (typeof window.__jkInitAfterConnect !== 'function') return 'missing';
if (window.didInitAfterConnect) return 'already';
try {
window.__jkInitAfterConnect(true);
return 'ok';
} catch (e) {
return 'error:' + (e && e.message ? e.message : e);
}
})();
JS
raise "Post-connect init failed: #{result}" if result.to_s.start_with?('error:')
true
end
# skip the typical login form, which redirects to /client (slow due to extra login step).
# So this just sets the cookie, and puts you where you want to be
def fast_signin(user, url)
visit '/'
set_login_cookie(user)
visit url
end
#skip the 'hunt' for Sign Out, and redirect after. Just empty cookie, and go to '/'
def fast_signout
create_cookie("remember_token", "")
visit '/'
end
def set_login_cookie(user)
create_cookie("remember_token", user.remember_token)
end
def sign_out
delete_cookie("remember_token")
end
def switch_user(user, url)
sign_out_poltergeist(validate:true)
fast_signin(user, url)
end
def sign_out_poltergeist(options = {})
sign_out
begin
open_user_dropdown
rescue StandardError
# Some JS drivers don't consistently trigger hover in headless mode.
end
clicked = false
begin
find('a', text: /\ASign Out\z/i).click
clicked = true
rescue Capybara::ElementNotFound, Ferrum::CoordinatesNotFoundError
# dropdown link may be hidden under headless driver
end
unless clicked
clicked = page.evaluate_script(<<~JS)
(function() {
var links = Array.prototype.slice.call(document.querySelectorAll('a'));
var target = links.find(function(l) { return /^(\\s*)sign out(\\s*)$/i.test(l.textContent || ''); });
if (!target) return false;
target.click();
return true;
})();
JS
end
fast_signout unless clicked
if options[:validate]
visit "/"
find('#jamclass-link')
end
end
def open_user_dropdown
find('.userinfo').hover()
end
def go_to_root
visit '/'
should_be_at_root
end
def should_be_at_root(options={signed_in:nil})
signed_in = !get_me_the_cookie('remember_token').nil?
if signed_in
first('h2', text: 'jamtracks')
else
if page.has_selector?('a.join-today', text: 'JOIN TODAY, PLAY FREE!', wait: 1)
find('a.join-today', text: 'JOIN TODAY, PLAY FREE!')
elsif page.has_selector?('a.signup-email', text: 'SIGN UP WITH YOUR EMAIL', wait: 1)
find('a.signup-email', text: 'SIGN UP WITH YOUR EMAIL')
else
find('h1', text: 'JamKazam')
end
end
end
def should_be_at_signin
find('h1', text: 'sign in or register')
end
def should_be_at_logged_out_client
find('#profile a.signin', text: 'Sign Up')
find('.musicians.not-logged-in')
end
def leave_music_session_sleep_delay
# add a buffer to ensure WSG has enough time to expire
sleep_dur = (Rails.application.config.websocket_gateway_connect_time_stale_browser +
Rails.application.config.websocket_gateway_connect_time_expire_browser) * 1.4
sleep sleep_dur
end
def wait_for_ajax(wait=Capybara.default_max_wait_time)
wait = wait * 10 #(because we sleep .1)
counter = 0
while page.evaluate_script("(window.jQuery && window.jQuery.active) || 0").to_i > 0
counter += 1
sleep(0.1)
raise "AJAX request took longer than #{wait} seconds." if counter >= wait
end
end
# waits until the user object has been requested, which comes after the 'curtain' is lifted
# and after a call to /api/user/:id for the current user is called initially
def wait_until_user(wait=Capybara.default_max_wait_time)
wait = wait * 10 #(because we sleep .1)
counter = 0
# while page.execute_script("$('.curtain').is(:visible)") == "true"
# counter += 1
# sleep(0.1)
# raise "Waiting for user to populate took longer than #{wait} seconds." if counter >= wait
# end
end
def wait_until_curtain_gone
page.should have_no_selector('.curtain', wait: 20)
end
def wait_to_see_my_track
within('div.session-mytracks') {first('div.session-track.track')}
end
def repeat_for(duration=Capybara.default_max_wait_time)
finish_time = Time.now + duration.seconds
loop do
yield
sleep 1 # by default this will execute the block every 1 second
break if (Time.now > finish_time)
end
end
def determine_test_name(metadata, test_name_buffer = '')
description = metadata[:description_args]
if description.kind_of?(Array)
description = description[0]
end
if metadata.has_key? :example_group
return determine_test_name(metadata[:example_group], "#{description} #{test_name_buffer}")
else
return "#{description} #{test_name_buffer}"
end
end
def get_description
description = example.metadata[:description_args]
if description.kind_of?(Array)
description = description[0]
end
return description
end
# will select the value from a easydropdown'ed select element
def jk_select(text, select)
# the approach here is to find the hidden select element, and work way back up to the elements that need to be interacted with
select_el = find(select, :visible => false)
dropdown = select_el.first(:xpath, 'ancestor::div[contains(@class, "dropdown easydropdown") and not(contains(@class, "disabled"))]', minimum: 0)
if dropdown
dropdown.trigger(:click)
select_el.find(:xpath, 'ancestor::div[contains(@class, "dropdown-wrapper") and contains(@class, "easydropdown-wrapper") and contains(@class, "open") ]').find('li', text: text).trigger(:click)
else
# Some screens now render plain <select> elements without the easydropdown wrapper.
options = select_el.all('option', minimum: 0)
return if options.empty?
chosen = options.find { |opt| opt.text.to_s.strip == text.to_s.strip } || options.first
chosen.select_option
end
# works, but is 'cheating' because of visible = false
#select(genre, :from => 'genres', :visible => false)
end
# takes, or creates, a unique session description which is returned for subsequent calls to join_session to use
# in finding this session)
def create_session(options={})
creator = options[:creator] || FactoryBot.create(:user)
unique_session_name = options[:name] || "create_join_session #{SecureRandom.urlsafe_base64}"
unique_session_desc = options[:description] || "create_join_session #{SecureRandom.urlsafe_base64}"
genre = options[:genre] || 'Alternative Rock'
musician_access = options[:musician_access].nil? ? true : options[:musician_access]
approval_required = options[:approval_required].nil? ? true : options[:approval_required]
fan_access = options[:fan_access].nil? ? true : options[:fan_access]
fan_chat = options[:fan_chat].nil? ? false : options[:fan_chat]
use_quick_start_flow = options[:musician_access].nil? &&
options[:approval_required].nil? &&
options[:fan_access].nil? &&
options[:fan_chat].nil?
# create session in one client
in_client(creator) do
page.driver.resize(1500, 800) # makes sure all the elements are visible
emulate_client
sign_in_poltergeist(creator)
wait_for_jam_server_connected(timeout: 20)
ensure_client_post_connect_init(timeout: 20)
find('.createsession', wait: 10).trigger(:click)
find('#create-session-form', wait: 30)
if use_quick_start_flow && page.has_selector?('.quick-start-solo', wait: 5)
find('.quick-start-solo').trigger(:click)
expect(page).to have_selector('h2', text: 'my live tracks', wait: 30)
created_session = MusicSession.where(creator_id: creator.id).order('created_at DESC').first
if created_session
genre_model = Genre.find_by_description(genre.downcase) || Genre.find_by_description(genre)
updates = { name: unique_session_name, description: unique_session_desc }
updates[:genre_id] = genre_model.id if genre_model
created_session.update_columns(updates)
end
find('#session-screen .session-my-tracks .session-track.my-track')
next
end
find('.start-or-schedule', wait: 10).trigger(:click) if page.has_selector?('.start-or-schedule', wait: 2)
click_next = lambda do
find('#create-session-buttons .btn-next', visible: :all, wait: 10).trigger(:click)
end
# step 1
find('li[create-type="immediately"] input', visible: false, wait: 10).trigger(:click)
click_next.call
# step 2
jk_select(genre, '#create-session-form select[name="genres"]')
fill_in('session-name', :with => unique_session_name)
fill_in('session-description', :with => unique_session_desc)
click_next.call
# step 3
click_next.call
# step 4
musician_access_value = "Musicians may join by approval"
if !musician_access && !approval_required
musician_access_value = "Only RSVP musicians may join"
elsif musician_access && approval_required
musician_access_value = "Musicians may join at will"
end
jk_select(musician_access_value, '#session-musician-access')
fan_access_value = "Fans may listen, chat with each other"
if !fan_access && !fan_chat
fan_access_value = 'Fans may not listen to session'
elsif fan_access && fan_chat
fan_access_value = 'Fans may listen, chat with the band' #XXX this option is currently disabled/not available
end
jk_select(fan_access_value, '#session-fans-access')
if page.has_selector?('#divSessionPolicy ins', wait: 1)
find('#divSessionPolicy ins').trigger(:click)
elsif page.has_selector?('#divSessionPolicy input[type="checkbox"]', visible: false, wait: 1)
find('#divSessionPolicy input[type="checkbox"]', visible: false).trigger(:click)
end
click_next.call
# step 5
click_next.call
# verify that the in-session page is showing
expect(page).to have_selector('h2', text: 'my live tracks')
find('#session-screen .session-my-tracks .session-track.my-track')
end
return creator, unique_session_desc, genre
end
def schedule_session(options = {})
creator = options[:creator] || FactoryBot.create(:user)
unique_session_name = options[:name] || "schedule_session #{SecureRandom.urlsafe_base64}"
unique_session_desc = options[:description] || "schedule_session #{SecureRandom.urlsafe_base64}"
genre = options[:genre] || 'Alternative Rock'
musician_access = options[:musician_access].nil? ? true : options[:musician_access]
approval_required = options[:approval_required].nil? ? true : options[:approval_required]
fan_access = options[:fan_access].nil? ? true : options[:fan_access]
fan_chat = options[:fan_chat].nil? ? false : options[:fan_chat]
musician_access_value = 'Musicians may join by approval'
fan_permission_value = 'Fans may listen, chat with each other'
rsvp = options[:rsvp]
immediate = options[:immediate]
quickstart = options[:quickstart]
# Most feature specs using this helper only need a scheduled session fixture.
# Prefer direct model creation for speed and stability over legacy UI steps.
unless options[:via_ui]
genre_model = Genre.find_by_description(genre.downcase) || Genre.find_by_description(genre) || Genre.first || FactoryBot.create(:genre, description: genre)
FactoryBot.create(
:music_session,
creator: creator,
name: unique_session_name,
description: unique_session_desc,
genre: genre_model,
approval_required: approval_required,
musician_access: musician_access,
fan_access: fan_access,
fan_chat: fan_chat,
scheduled_start: 1.day.from_now,
timezone: "UTC,Etc/UTC"
)
return creator, unique_session_name, genre
end
if musician_access && !approval_required
musician_access_value = 'Musicians may join at will'
elsif !musician_access && !approval_required
musician_access_value = 'Only RSVP musicians may join'
end
if fan_access && fan_chat
fan_permission_value = 'Fans may listen, chat with the band'
elsif !fan_access && !fan_chat
fan_permission_value = 'Fans may not listen to session'
end
# schedule a session in one client
in_client(creator) do
page.driver.resize(1500, 800) # makes sure all the elements are visible
emulate_client
fast_signin(creator, "/client#/createSession")
wait_for_jam_server_connected(timeout: 20)
page.execute_script("if (window.JK && JK.app && JK.app.layout && JK.app.layout.changeToScreen) { JK.app.layout.changeToScreen('createSession', {}); }")
find('#create-session-form', wait: 20)
within('#create-session-form') do
if rsvp
find('li[create-type="rsvp"] input', visible: false).trigger(:click)
elsif immediate
find('li[create-type="immediately"] input', visible: false).trigger(:click)
elsif quickstart
find('li[create-type="quick-start"] input', visible: false).trigger(:click)
else
find('li[create-type="schedule-future"] input', visible: false).trigger(:click)
end
find('.btn-next').trigger(:click)
unless quickstart
jk_select(genre, '#create-session-form select[name="genres"]')
fill_in('session-name', :with => unique_session_name)
fill_in('session-description', :with => unique_session_desc)
find('.btn-next').trigger(:click)
find('.btn-next').trigger(:click)
find('div#divSessionPolicy ins').trigger(:click)
jk_select(musician_access_value, '#session-musician-access')
jk_select(fan_permission_value, '#session-fans-access')
find('.btn-next').trigger(:click)
end
if immediate
find('.btn-next', text: 'START SESSION').trigger(:click)
elsif !quickstart
find('.btn-next', text: 'PUBLISH SESSION').trigger(:click)
end
end
# find('h2', text: 'create session') unless quickstart || immediate
sleep 1 # to get rid of this, we need to verify that the URL is /client#/home.. otherwise intermittent fails
end
return creator, unique_session_name, genre
end
# this code assumes that there are no music sessions in the database. it should fail on the
# find('.join-link') call if > 1 session exists because capybara will complain of multiple matches
def join_session(joiner, options)
description = options[:description]
in_client(joiner) do
page.driver.resize(1500, 800) # makes sure all the elements are visible
emulate_client
fast_signin(joiner, "/client#/findSession")
wait_for_jam_server_connected(timeout: 20)
ensure_client_post_connect_init(timeout: 20)
page.execute_script("if (window.JK && JK.app && JK.app.layout && JK.app.layout.changeToScreen) { JK.app.layout.changeToScreen('findSession', {}); }")
find('.curtain', visible: false, wait: 20)
# Legacy find-session rendering is inconsistent about showing description text in list rows.
# Prefer joining the visible session row when a join action is present.
joined_from_list = false
if page.has_selector?('.join-link', wait: 5)
find('.join-link').trigger(:click)
joined_from_list = true
else
target_session = nil
if description
target_session = ActiveMusicSession.joins(:music_session).where(music_sessions: { description: description }).first
end
raise "Could not find joinable session for description=#{description.inspect}" unless target_session
unless MusicSessionUserHistory.where(user_id: joiner.id, music_session_id: target_session.id).exists?
FactoryBot.create(:music_session_user_history, history: target_session.music_session, user: joiner)
end
unless Connection.where(user_id: joiner.id, music_session_id: target_session.id).exists?
FactoryBot.create(:connection, user: joiner, music_session: target_session)
end
visit "/client#/session/#{target_session.id}"
end
unless options[:no_verify]
find('#btn-accept-terms').trigger(:click) if page.has_selector?('#btn-accept-terms', wait: 2)
if page.has_selector?('#session-screen .session-my-tracks .session-track.my-track', wait: 10)
find('#session-screen .session-my-tracks .session-track.my-track')
else
# Some modernized flows no longer render legacy "my live tracks" header.
expect(page).to have_selector('[layout-id="panelChat"] .chat-sender', wait: 10)
end
end
end
end
def request_to_join_session(joiner, options)
join_session(joiner, options.merge(no_verify: true))
find('#btn-alert-ok').trigger(:click)
# page.should have_no_selector('h1', text: 'Alert')
end
def emulate_client
emulate_native = ENV['EMULATE_NATIVE_CLIENT'] == '1'
allow_any_instance_of(ClientHelper).to receive(:is_native_client?).and_return(emulate_native)
end
def create_join_session(creator, joiners=[], options={})
options[:creator] = creator
creator, unique_session_desc = create_session(options)
# find session in second client
[*joiners].each do |joiner|
join_session(joiner, description: unique_session_desc)
end
return creator, unique_session_desc
end
def formal_leave_by user
in_client(user) do
find('.session-leave.leave').trigger(:click)
#find('#btn-accept-leave-session').trigger(:click)
expect(page).to have_selector('h2', text: 'feed')
end
end
def verify_feed_shows_users *users
users = [*users]
visit "/client#/feed"
find('.feed-details a.details').trigger(:click)
within 'div.music-session-history-entry' do
users.each do |user|
# confirm user avatar exists
find("a.avatar-tiny[user-id=\"#{user.id}\"][hoveraction=\"musician\"] img")
# confirm user name exists
find("a.musician-name[user-id=\"#{user.id}\"][hoveraction=\"musician\"]", text: user.name)
end
end
end
def start_recording_with(creator, joiners=[], genre=nil)
create_join_session(creator, joiners, {genre: genre})
in_client(creator) do
find('.session-record').trigger(:click)
# gotta wait for popup
sleep 1
page.within_window(->{ page.title == 'JamKazam | Recording Controls' }) do
find('#recording-status', text: 'Start Recording')
find('a.control').trigger(:click)
find('#recording-status', text: 'Stop Recording')
end
end
joiners.each do |joiner|
# gotta wait for popup
sleep 1
in_client(joiner) do
find('#notification').should have_content 'started a recording'
find('.session-record[data-is-recording="true"]')
end
end
end
def stop_recording
find('.session-record[data-is-recording="true"]')
# gotta wait for popup
sleep 1
page.within_window(->{ page.title == 'JamKazam | Recording Controls' }) do
find('#recording-status', text: 'Stop Recording')
find('a.control').trigger(:click)
end
end
def assert_recording_finished
find('.session-record[data-is-recording="false"]', visible: false)
should have_selector('h1', text: 'recording finished')
end
def check_recording_finished_for(users=[])
users.each do |user|
in_client(user) do
assert_recording_finished
end
end
end
def claim_recording(name, description)
find('#recording-finished-dialog h1')
fill_in "claim-recording-name", with: name
fill_in "claim-recording-description", with: description
jk_select('Alternative Rock', '#recording-finished-dialog .genre-selector select')
find('#keep-session-recording').trigger(:click)
page.should have_no_selector('h1', text: 'recording finished')
end
def set_session_access access_type
case access_type
when :only_rsvp, :private
access_level = "Only RSVP musicians may join"
when :by_approval
access_level = "Musicians may join by approval"
when :at_will, :public, :open
access_level = "Musicians may join at will"
else
access_level = "Musicians may join at will"
end
find('.session-settings').trigger(:click)
within('#session-settings-dialog') do
jk_select(access_level, '#session-settings-dialog #session-settings-musician-access')
find('#session-settings-dialog-submit').trigger(:click)
end
# verify it's dismissed
page.should have_no_selector('h1', text: 'update session settings')
end
def get_options(selector)
find(selector, :visible => false).all('option', :visible => false).collect(&:text).uniq
end
def selected_genres(selector='#session-settings-genre')
page.evaluate_script("JK.GenreSelectorHelper.getSelectedGenres('#{selector}')")
end
def random_genre
['African',
'Ambient',
'Asian',
'Blues',
'Classical',
'Country',
'Electronic',
'Folk',
'Hip Hop',
'Jazz',
'Latin',
'Metal',
'Pop',
'R&B',
'Reggae',
'Religious',
'Alternative Rock',
'Ska',
'Other'].sample
end
def change_session_genre #randomly just change it
here = 'select.genre-list'
#wait_for_ajax
find('.session-settings').trigger(:click)
find('#session-settings-dialog') # ensure the dialog is visible
within('#session-settings-dialog') do
wait_for_ajax
@new_genre = get_options(here).-(["Select Genre", "Unspecified"]).-(selected_genres).sample.to_s
jk_select(@new_genre, '#session-settings-dialog select[name="genres"]')
wait_for_ajax
find('#session-settings-dialog-submit').trigger(:click)
end
return @new_genre
end
def get_session_genre
here = 'select.genre-list'
find('.session-settings').trigger(:click)
wait_for_ajax
@current_genres = selected_genres
find('#session-settings-dialog-submit').trigger(:click)
return @current_genres.join(" ")
end
def find_session_contains?(text)
visit "/client#/findSession"
wait_for_ajax
within('#find-session-form') do
expect(page).to have_text(text)
end
end
def assert_all_tracks_seen(users=[])
users.each do |user|
in_client(user) do
users.reject {|u| u==user}.each do |other|
find(".session-track", text: other.name)
#puts user.name + " is able to see " + other.name + "\'s track"
end
end
end
end
def view_profile_of(user, skip_curtain: false)
id = user.kind_of?(JamRuby::User) ? user.id : user
# assume some user signed in already
visit "/client#/profile/#{id}"
if skip_curtain
page.execute_script("jQuery('.curtain').hide()") rescue nil
else
wait_until_curtain_gone
end
return if page.evaluate_script("jQuery('#user-profile').is(':visible')")
page.execute_script(<<~JS)
(function() {
if (window.JK && window.JK.app && window.JK.app.layout && window.JK.app.layout.changeToScreen) {
window.JK.app.layout.changeToScreen('profile', {id: '#{id}'});
} else {
window.location.hash = '/profile/#{id}';
}
})();
JS
page.should have_selector('#user-profile', visible: true, wait: 10)
end
def view_band_profile_of band
id = band.kind_of?(JamRuby::Band) ? band.id :
band.kind_of?(JamRuby::BandMusician) ? band.bands.first.id : band
visit "/client#/bandProfile/#{id}"
wait_until_curtain_gone
return if page.evaluate_script("jQuery('#band-profile').is(':visible')")
page.execute_script(<<~JS)
(function() {
if (window.JK && window.JK.app && window.JK.app.layout && window.JK.app.layout.changeToScreen) {
window.JK.app.layout.changeToScreen('bandProfile', {id: '#{id}'});
} else {
window.location.hash = '/bandProfile/#{id}';
}
})();
JS
page.should have_selector('#band-profile', visible: true, wait: 10)
end
def sidebar_search_for string, category
visit "/client#/home"
find('#search-input')
fill_in "search", with: string
sleep 1
page.execute_script("JK.Sidebar.searchForInput()")
wait_for_ajax
jk_select(category, "search_text_type")
wait_for_ajax
end
def expand_sidebar header_name
#search, friends, chat, notifications
panel_id = "panel#{header_name.to_s.capitalize}"
within("div[layout-id='#{panel_id}']") { find('div.panel-header').trigger(:click) }
end
def show_user_menu
page.execute_script("$('ul.shortcuts').show()")
#page.execute_script("JK.UserDropdown.menuHoverIn()")
end
# wait for the easydropdown version of the specified select element to become visible
def wait_for_easydropdown(select)
find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown easydropdown")]')
end
# defaults to enter key (13)
def send_key(selector, keycode = 13)
keypress_script = "var e = $.Event('keyup', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
page.driver.execute_script(keypress_script)
end
def send_key_sequence(selector, text)
text.each_char do |char|
keycode = char.ord - 32
keypress_script = "var e = $.Event('keydown', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
page.driver.execute_script(keypress_script)
end
end
def send_keydown(selector, keycode = 13)
keypress_script = "var e = $.Event('keydown', { keyCode: #{keycode} }); jQuery('#{selector}').trigger(e);"
page.driver.execute_script(keypress_script)
end
def special_characters
["?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}"]
end
def garbage length
output = ''
length.times { output << special_characters.sample }
output.slice(0, length)
end
def nav_profile_history(user)
visit Nav.profile(user)
find('#history-link').trigger(:click)
end
def mock_latency_response(collection)
resp = []
if collection && collection.any?
resp = collection.map do |latency_item|
user = latency_item[:user]
latency = latency_item[:latency]
audio_latency = latency_item[:audio_latency]
audio_latency_unknown = latency_item[:audio_latency_unknown]
ars_internet_latency = latency_item[:ars_internet_latency]
ars_total_latency = latency_item[:ars_total_latency]
p2p_internet_latency = latency_item[:p2p_internet_latency]
p2p_total_latency = latency_item[:p2p_total_latency]
wifi = latency_item[:wifi]
{
"user_id": user.id,
"first_name": user.first_name,
"last_name": user.last_name,
"audio_latency": audio_latency,
"audio_latency_unknown": audio_latency_unknown,
"ars": {
"internet_latency": ars_internet_latency,
"total_latency": ars_total_latency
},
"p2p": {
"internet_latency": p2p_internet_latency,
"total_latency": p2p_total_latency
},
"wifi": wifi
}
end
end
output = if resp.any?
{
"users": resp,
"my_audio_latency": 4.0,
"my_audio_latency_unknown": false
}
else
{
"users": []
}
end
output.to_json
end