lib/calabash.rb in calabash-1.2.1 vs lib/calabash.rb in calabash-1.9.9.pre1

- old
+ new

@@ -1,184 +1,368 @@ -require 'calabash/version' +# Calabash is a Behavior-driven development (BDD) framework for Android and +# iOS. It supports both native and hybrid app testing. +# +# It is developed and maintained by Xamarin and is released under the Eclipse +# Public License. +module Calabash + require 'calabash/patch/run_loop' + require 'calabash/version' + require 'calabash/environment' + require 'calabash/logger' + require 'calabash/color' + require 'calabash/utility' + require 'calabash/application' + require 'calabash/device' + require 'calabash/http' + require 'calabash/server' + require 'calabash/wait' + require 'calabash/query' + require 'calabash/query_result' + require 'calabash/screenshot' + require 'calabash/gestures' + require 'calabash/life_cycle' + require 'calabash/location' + require 'calabash/orientation' + require 'calabash/query' + require 'calabash/text' + require 'calabash/interactions' + require 'calabash/defaults' + require 'calabash/console_helpers' + + + require 'calabash/patch' + Calabash::Patch.apply_patches! + + + include Utility + include Calabash::Wait + include Calabash::Screenshot + include Calabash::Gestures + include Calabash::LifeCycle + include Calabash::Location + include Calabash::Orientation + include Calabash::Text + include Calabash::Interactions + extend Calabash::Defaults + + require 'calabash/page' + + # Instantiate a page object. + # + # @example + # # android/pages/login_page.rb + # class Android::LoginPage < Calabash::Page + # include Calabash::Android + # + # [...] + # end + # + # # step definition + # Given([...]) do + # # Calabash will determine your platform and pick the Android page. + # page(LoginPage).method + # end + # + # @param [Class] The page to instantiate + # @return [Calabash::Page] An instance of the page class + def page(page_class) + platform_module = if Device.default.is_a?(Android::Device) + Object.const_get(:Android) + elsif Device.default.is_a?(IOS::Device) + Object.const_get(:IOS) + else + raise 'Cannot detect running platform' + end + + unless page_class.is_a?(Class) + raise ArgumentError, "Expected a 'Class', got '#{page_class.class}'" + end + + page_name = page_class.name.split('::').last + + if platform_module.const_defined?(page_name, false) + page_class = platform_module.const_get(page_name, false) + + if page_class.is_a?(Class) + page = page_class.send(:new, self) + + if page.is_a?(Calabash::Page) + page + else + raise "Page '#{page_class}' is not a Calabash::Page" + end + else + raise "Page '#{page_class}' is not a class" + end + else + raise "No such page defined '#{platform_module}::#{page_name}'" + end + end + + def self.new_embed_method!(method) + EmbeddingContext.new_embed_method(method) + end + + # @!visibility private + def self.add_embed_method(base, method) + # These methods will be invoked **before** the base module is mutated. + # This means that no methods defined in the base module stem from Calabash + # yet. + unless base.respond_to?(:embed) + # The 'embed' method was not defined in the including base module. We + # don't want to define embed as Calabash's own method, as Calabash should + # not be globally mutated because of this include/extend. Notice that the + # embedding context might be mutated. e.g. when Calabash detects it is + # running in the context of Cucumber. Ruby acknowledges this change in + # all modules that include/extend the EmbeddingContext module. + base.send(method, EmbeddingContext) + end + end + + # @!visibility private + def self.included(base) + if base.to_s == 'Calabash::Android' || base.to_s == 'Calabash::IOS' + return + end + + add_embed_method(base, :include) + end + + # @!visibility private + def self.extended(base) + # We would like to use Cucumber's embed method if possible. + # This is a hook to obtain this method + if base.singleton_class.included_modules.map(&:to_s).include?('Cucumber::RbSupport::RbWorld') + on_cucumber_context(base) + else + add_embed_method(base, :extend) + end + end + + private + + # @!visibility private + def self.on_new_context(base) + cucumber_embed = base.method(:embed) + + unless EmbeddingContext.embedding_context_set? + new_embed_method!(cucumber_embed) + end + end + + # @!visibility private + def self.on_cucumber_context(base) + on_new_context(base) + end + + # @!visibility private + module EmbeddingContext + @@has_set_embedding_context ||= false + + def self.embedding_context_set? + @@has_set_embedding_context + end + + def self.new_embed_method(method) + define_method(:embed) do |*args| + method.call(*args) + end + + @@has_set_embedding_context = true + end + + def embed(*_) + Logger.warn 'Embed is not available in this context. Will not embed.' + end + end +end + +unless Object.const_defined?(:Android) + Object.const_set(:Android, Module.new) +end + +unless Object.const_defined?(:IOS) + Object.const_set(:IOS, Module.new) +end