ruby_raider 3.13.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/runtime.yml +38 -0
- data/.github/workflows/system_tests.yml +1 -23
- data/.reek.yml +1 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/README.md +16 -49
- data/RELEASE.md +22 -0
- data/bin/raider +5 -0
- data/lib/commands/scaffolding_commands.rb +2 -25
- data/lib/commands/utility_commands.rb +23 -3
- data/lib/generators/automation/automation_generator.rb +0 -5
- data/lib/generators/automation/templates/component.tt +1 -0
- data/lib/generators/automation/templates/home.tt +2 -2
- data/lib/generators/automation/templates/login.tt +6 -26
- data/lib/generators/automation/templates/page.tt +23 -18
- data/lib/generators/automation/templates/partials/home_page_selector.tt +1 -2
- data/lib/generators/automation/templates/partials/initialize_selector.tt +0 -8
- data/lib/generators/automation/templates/partials/pdp_page_selector.tt +1 -2
- data/lib/generators/automation/templates/partials/url_methods.tt +8 -2
- data/lib/generators/automation/templates/partials/visit_method.tt +0 -5
- data/lib/generators/automation/templates/pdp.tt +1 -9
- data/lib/generators/common_generator.rb +0 -2
- data/lib/generators/generator.rb +12 -19
- data/lib/generators/helper_generator.rb +21 -19
- data/lib/generators/infrastructure/templates/azure_pipelines.tt +1 -1
- data/lib/generators/infrastructure/templates/github.tt +2 -3
- data/lib/generators/infrastructure/templates/github_appium.tt +0 -8
- data/lib/generators/invoke_generators.rb +4 -23
- data/lib/generators/menu_generator.rb +1 -9
- data/lib/generators/rspec/templates/accessibility_spec.tt +1 -9
- data/lib/generators/rspec/templates/spec.tt +8 -24
- data/lib/generators/template_renderer/partial_cache.rb +3 -1
- data/lib/generators/template_renderer.rb +1 -1
- data/lib/generators/templates/common/gemfile.tt +3 -10
- data/lib/generators/templates/common/git_ignore.tt +0 -5
- data/lib/generators/templates/common/partials/mobile_config.tt +3 -1
- data/lib/generators/templates/common/partials/web_config.tt +10 -1
- data/lib/generators/templates/common/rakefile.tt +0 -15
- data/lib/generators/templates/common/read_me.tt +357 -250
- data/lib/generators/templates/common/rubocop.tt +0 -2
- data/lib/generators/templates/helpers/driver_helper.tt +8 -0
- data/lib/generators/templates/helpers/gesture_helper.tt +78 -0
- data/lib/generators/templates/helpers/network_helper.tt +521 -0
- data/lib/generators/templates/helpers/partials/quit_driver.tt +0 -2
- data/lib/generators/templates/helpers/partials/screenshot.tt +0 -2
- data/lib/generators/templates/helpers/partials/selenium_driver.tt +5 -2
- data/lib/generators/templates/helpers/screenshot_helper.tt +490 -0
- data/lib/generators/templates/helpers/spec_helper.tt +39 -29
- data/lib/generators/templates/helpers/trace_helper.tt +240 -95
- data/lib/generators/templates/helpers/video_helper.tt +3 -8
- data/lib/ruby_raider/runtime/actionability.rb +129 -0
- data/lib/ruby_raider/runtime/actionable.rb +49 -0
- data/lib/ruby_raider/runtime/by_role.rb +55 -0
- data/lib/ruby_raider/runtime/config.rb +79 -0
- data/lib/ruby_raider/runtime/context.rb +38 -0
- data/lib/ruby_raider/runtime/errors.rb +69 -0
- data/lib/ruby_raider/runtime/finders.rb +73 -0
- data/lib/ruby_raider/runtime/js/actionability.js +134 -0
- data/lib/ruby_raider/runtime/js/role_engine.js +315 -0
- data/lib/ruby_raider/runtime/locator_converter.rb +72 -0
- data/lib/ruby_raider/runtime/matchers/base.rb +222 -0
- data/lib/ruby_raider/runtime/matchers/element.rb +183 -0
- data/lib/ruby_raider/runtime/matchers/page.rb +71 -0
- data/lib/ruby_raider/runtime/matchers/presence.rb +41 -0
- data/lib/ruby_raider/runtime/matchers/retrying_block.rb +104 -0
- data/lib/ruby_raider/runtime/observer.rb +170 -0
- data/lib/ruby_raider/runtime/role_finder.rb +83 -0
- data/lib/ruby_raider/runtime/rspec.rb +78 -0
- data/lib/ruby_raider/runtime/selectors.rb +60 -0
- data/lib/ruby_raider/runtime/strict.rb +142 -0
- data/lib/ruby_raider/runtime/wait.rb +84 -0
- data/lib/ruby_raider/runtime.rb +20 -0
- data/lib/scaffolding/name_normalizer.rb +1 -1
- data/lib/scaffolding/project_detector.rb +2 -28
- data/lib/scaffolding/scaffolding.rb +0 -20
- data/lib/scaffolding/templates/component.tt +0 -14
- data/lib/scaffolding/templates/page_object.tt +2 -14
- data/lib/scaffolding/templates/spec.tt +1 -9
- data/lib/utilities/utilities.rb +10 -8
- data/lib/version +1 -1
- data/ruby_raider.gemspec +2 -1
- data/sig/commands/scaffolding_commands.rbs +0 -2
- data/sig/commands/utility_commands.rbs +6 -0
- data/sig/generators/generator.rbs +0 -4
- data/sig/generators/helper_generator.rbs +0 -1
- data/sig/generators/menu_generator.rbs +0 -1
- data/sig/ruby_raider/runtime/actionability.rbs +25 -0
- data/sig/ruby_raider/runtime/actionable.rbs +13 -0
- data/sig/ruby_raider/runtime/by_role.rbs +15 -0
- data/sig/ruby_raider/runtime/config.rbs +26 -0
- data/sig/ruby_raider/runtime/context.rbs +12 -0
- data/sig/ruby_raider/runtime/errors.rbs +36 -0
- data/sig/ruby_raider/runtime/finders.rbs +26 -0
- data/sig/ruby_raider/runtime/locator_converter.rbs +21 -0
- data/sig/ruby_raider/runtime/matchers/base.rbs +64 -0
- data/sig/ruby_raider/runtime/matchers/element.rbs +78 -0
- data/sig/ruby_raider/runtime/matchers/page.rbs +38 -0
- data/sig/ruby_raider/runtime/matchers/presence.rbs +21 -0
- data/sig/ruby_raider/runtime/matchers/retrying_block.rbs +27 -0
- data/sig/ruby_raider/runtime/observer.rbs +46 -0
- data/sig/ruby_raider/runtime/role_finder.rbs +18 -0
- data/sig/ruby_raider/runtime/selectors.rbs +21 -0
- data/sig/ruby_raider/runtime/strict.rbs +35 -0
- data/sig/ruby_raider/runtime/wait.rbs +17 -0
- data/sig/ruby_raider/runtime.rbs +2 -0
- data/sig/scaffolding/project_detector.rbs +0 -4
- data/sig/scaffolding/scaffolding.rbs +0 -5
- data/sig/utilities/utilities.rbs +2 -1
- data/sig/vendor/selenium_webdriver.rbs +71 -0
- data/spec/commands/raider_commands_spec.rb +38 -3
- data/spec/commands/scaffolding_commands_spec.rb +27 -0
- data/spec/commands/utility_commands_spec.rb +53 -0
- data/spec/generators/gesture_helper_spec.rb +123 -0
- data/spec/generators/network_helper_spec.rb +634 -0
- data/spec/generators/screenshot_helper_spec.rb +776 -0
- data/spec/generators/template_renderer_spec.rb +0 -4
- data/spec/generators/trace_helper_spec.rb +489 -97
- data/spec/generators/video_helper_spec.rb +0 -9
- data/spec/integration/commands/browser_update_after_creation_spec.rb +0 -8
- data/spec/integration/commands/scaffolding_commands_spec.rb +12 -70
- data/spec/integration/commands/utility_commands_spec.rb +19 -41
- data/spec/integration/content/azure_content_spec.rb +2 -6
- data/spec/integration/content/ci_content_spec.rb +1 -55
- data/spec/integration/content/common_content_spec.rb +1 -118
- data/spec/integration/content/config_content_spec.rb +34 -31
- data/spec/integration/content/gemfile_content_spec.rb +7 -72
- data/spec/integration/content/helper_content_spec.rb +105 -99
- data/spec/integration/content/page_content_spec.rb +85 -87
- data/spec/integration/content/readme_content_spec.rb +134 -75
- data/spec/integration/content/rspec_reporter_content_spec.rb +2 -2
- data/spec/integration/content/rubocop_content_spec.rb +1 -1
- data/spec/integration/content/syntax_validation_spec.rb +2 -2
- data/spec/integration/content/test_content_spec.rb +23 -147
- data/spec/integration/end_to_end_features_spec.rb +1 -43
- data/spec/integration/end_to_end_spec.rb +319 -326
- data/spec/integration/generators/automation_generator_spec.rb +3 -37
- data/spec/integration/generators/axe_addon_spec.rb +2 -35
- data/spec/integration/generators/azure_generator_spec.rb +1 -1
- data/spec/integration/generators/common_generator_spec.rb +1 -40
- data/spec/integration/generators/config_features_spec.rb +1 -24
- data/spec/integration/generators/github_generator_spec.rb +0 -12
- data/spec/integration/generators/helpers_generator_spec.rb +74 -80
- data/spec/integration/generators/invoke_generators_spec.rb +54 -45
- data/spec/integration/generators/rspec_generator_spec.rb +0 -6
- data/spec/integration/scaffolding_e2e_spec.rb +17 -179
- data/spec/integration/spec_helper.rb +4 -6
- data/spec/integration/trace_format_checker.rb +11 -2
- data/spec/integration/trace_page_server.rb +72 -5
- data/spec/menus/menu_generator_spec.rb +14 -39
- data/spec/runtime/actionability_spec.rb +207 -0
- data/spec/runtime/actionable_spec.rb +125 -0
- data/spec/runtime/browser/actionability_script_browser_spec.rb +150 -0
- data/spec/runtime/browser/actionable_browser_spec.rb +98 -0
- data/spec/runtime/browser/finders_browser_spec.rb +148 -0
- data/spec/runtime/browser/matchers_browser_spec.rb +67 -0
- data/spec/runtime/browser/retrying_block_browser_spec.rb +37 -0
- data/spec/runtime/browser/role_engine_browser_spec.rb +184 -0
- data/spec/runtime/browser/strict_browser_spec.rb +38 -0
- data/spec/runtime/by_role_spec.rb +52 -0
- data/spec/runtime/config_spec.rb +79 -0
- data/spec/runtime/context_spec.rb +73 -0
- data/spec/runtime/errors_spec.rb +89 -0
- data/spec/runtime/finders_spec.rb +165 -0
- data/spec/runtime/fixtures/actionability.html +70 -0
- data/spec/runtime/fixtures/locators.html +46 -0
- data/spec/runtime/fixtures/matchers.html +33 -0
- data/spec/runtime/fixtures/roles.html +162 -0
- data/spec/runtime/matchers/base_spec.rb +165 -0
- data/spec/runtime/matchers/element_spec.rb +277 -0
- data/spec/runtime/matchers/page_spec.rb +102 -0
- data/spec/runtime/matchers/presence_spec.rb +59 -0
- data/spec/runtime/matchers/retrying_block_spec.rb +165 -0
- data/spec/runtime/observer_spec.rb +341 -0
- data/spec/runtime/role_finder_spec.rb +156 -0
- data/spec/runtime/role_query_spec.rb +75 -0
- data/spec/runtime/selectors_spec.rb +135 -0
- data/spec/runtime/strict_spec.rb +257 -0
- data/spec/runtime/support/browser.rb +48 -0
- data/spec/runtime/support/fake_bridge.rb +117 -0
- data/spec/runtime/wait_spec.rb +71 -0
- data/spec/scaffolding/name_normalizer_spec.rb +3 -2
- data/spec/scaffolding/scaffold_project_detector_spec.rb +4 -43
- data/spec/system/selenium_spec.rb +1 -5
- data/spec/system/support/system_test_helper.rb +2 -5
- data/spec/utilities/headless_config_spec.rb +0 -7
- data/spec/utilities/utilities_spec.rb +24 -0
- metadata +113 -48
- data/lib/generators/automation/templates/header.tt +0 -9
- data/lib/generators/cucumber/cucumber_generator.rb +0 -58
- data/lib/generators/cucumber/templates/accessibility_feature.tt +0 -5
- data/lib/generators/cucumber/templates/accessibility_steps.tt +0 -17
- data/lib/generators/cucumber/templates/cucumber.tt +0 -1
- data/lib/generators/cucumber/templates/env.tt +0 -7
- data/lib/generators/cucumber/templates/feature.tt +0 -21
- data/lib/generators/cucumber/templates/partials/appium_env.tt +0 -26
- data/lib/generators/cucumber/templates/partials/driver_world.tt +0 -18
- data/lib/generators/cucumber/templates/partials/mobile_steps.tt +0 -20
- data/lib/generators/cucumber/templates/partials/selenium_env.tt +0 -120
- data/lib/generators/cucumber/templates/partials/watir_env.tt +0 -48
- data/lib/generators/cucumber/templates/partials/watir_world.tt +0 -4
- data/lib/generators/cucumber/templates/partials/web_steps.tt +0 -28
- data/lib/generators/cucumber/templates/steps.tt +0 -5
- data/lib/generators/cucumber/templates/user_factory.tt +0 -15
- data/lib/generators/cucumber/templates/world.tt +0 -7
- data/lib/generators/templates/helpers/browser_helper.tt +0 -31
- data/lib/generators/templates/helpers/raider_element.tt +0 -159
- data/lib/generators/templates/helpers/wait_helper.tt +0 -611
- data/lib/scaffolding/templates/feature.tt +0 -6
- data/lib/scaffolding/templates/steps.tt +0 -19
- data/sig/generators/cucumber/cucumber_generator.rbs +0 -12
- data/spec/fixtures/watir_master/cucumber_watir/Readme.md.snapshot +0 -175
- data/spec/fixtures/watir_master/cucumber_watir/features/step_definitions/login_steps.rb.snapshot +0 -24
- data/spec/fixtures/watir_master/cucumber_watir/page_objects/abstract/page.rb.snapshot +0 -37
- data/spec/fixtures/watir_master/cucumber_watir/page_objects/pages/login.rb.snapshot +0 -33
- data/spec/fixtures/watir_master/rspec_watir/Readme.md.snapshot +0 -174
- data/spec/fixtures/watir_master/rspec_watir/page_objects/abstract/page.rb.snapshot +0 -37
- data/spec/fixtures/watir_master/rspec_watir/page_objects/pages/login.rb.snapshot +0 -33
- data/spec/fixtures/watir_master/rspec_watir/spec/login_page_spec.rb.snapshot +0 -49
- data/spec/integration/content/cucumber_reporter_content_spec.rb +0 -161
- data/spec/integration/generators/cucumber_generator_spec.rb +0 -100
- data/spec/integration/helpers/wait_helper_mobile_spec.rb +0 -281
- data/spec/integration/helpers/wait_helper_spec.rb +0 -679
- data/spec/integration/helpers/wait_helper_support.rb +0 -183
- data/spec/system/watir_spec.rb +0 -38
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'content_helper'
|
|
4
|
-
|
|
5
|
-
describe 'Cucumber raider_reporter wiring' do
|
|
6
|
-
screenshot_calls = {
|
|
7
|
-
'selenium' => 'driver.save_screenshot(screenshot_path)',
|
|
8
|
-
'watir' => 'browser.screenshot.save(screenshot_path)'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
AUTOMATION_TYPES.each do |automation|
|
|
12
|
-
context "with cucumber and #{automation}" do
|
|
13
|
-
let(:project_name) { "#{FrameworkIndex::CUCUMBER}_#{automation}" }
|
|
14
|
-
let(:env) { read_generated(project_name, 'features/support/env.rb') }
|
|
15
|
-
let(:screenshot_call) { screenshot_calls.fetch(automation, 'driver.screenshot(screenshot_path)') }
|
|
16
|
-
let(:hook) { env[/^\s*After do.*\z/m] }
|
|
17
|
-
let(:quit_call) { automation == 'watir' ? 'browser.quit' : 'driver.quit' }
|
|
18
|
-
|
|
19
|
-
it 'activates the reporter by requiring raider_reporter/cucumber' do
|
|
20
|
-
expect(env).to include("require 'raider_reporter/cucumber'")
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'does not reference the allure helper' do
|
|
24
|
-
expect(env).not_to match(/AllureHelper|allure_helper/)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'takes the screenshot only for failed scenarios, inside the guard block' do
|
|
28
|
-
guarded = /if scenario\.failed\?\n\s+Dir\.mktmpdir do \|temp_folder\|\n(?<body>.*?)\n\s+end\n\s+end\nensure/m
|
|
29
|
-
expect(hook.match(guarded)[:body]).to include(screenshot_call)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'uses a fixed file name in the tmpdir, never the scenario name' do
|
|
33
|
-
expect(env).to include("screenshot_path = File.join(temp_folder, 'screenshot.png')")
|
|
34
|
-
expect(hook).not_to include('scenario.name')
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'quits the driver in an ensure of the After block, without a redundant begin' do
|
|
38
|
-
quit = %w[android ios cross_platform].include?(automation) ? 'driver.quit_driver' : quit_call
|
|
39
|
-
expect(hook).to match(/^\s*After do \|scenario\|\n.*\n^ensure\n.*\n\s+#{Regexp.escape(quit)}\nend/m)
|
|
40
|
-
expect(hook).not_to match(/^\s+begin$/)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it 'attaches the screenshot path before quitting the driver' do
|
|
44
|
-
attach = "RaiderReporter.attach('screenshot', screenshot_path, type: :png)"
|
|
45
|
-
expect(env).to include(attach)
|
|
46
|
-
expect(env.index(screenshot_call)).to be < env.index(attach)
|
|
47
|
-
expect(env.index(attach)).to be < env.index(/driver\.quit|browser\.quit/, env.index(attach))
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context 'with video recording' do
|
|
51
|
-
target = automation == 'watir' ? 'browser' : 'driver'
|
|
52
|
-
video_type = %w[selenium watir].include?(automation) ? ':webm' : ':mp4'
|
|
53
|
-
|
|
54
|
-
it 'requires video_helper' do
|
|
55
|
-
expect(env).to include("require_relative '../../helpers/video_helper'")
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'starts the recorder in Before' do
|
|
59
|
-
expect(env[/^Before do.*?^end$/m]).to include("@video_recorder = VideoHelper.recorder_for(#{target})", '@video_recorder.start')
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
it 'stops with keep: scenario.failed? before quitting, attaches the path and cleans up in the ensure' do
|
|
63
|
-
expect(hook).to include('video_path = @video_recorder&.stop(keep: scenario.failed?)')
|
|
64
|
-
expect(hook).to include("RaiderReporter.attach('video', video_path, type: #{video_type}) if video_path")
|
|
65
|
-
expect(hook.index('@video_recorder&.stop')).to be < hook.index("RaiderReporter.attach('video'")
|
|
66
|
-
expect(hook.index("RaiderReporter.attach('video'")).to be < hook.index(/^ensure/)
|
|
67
|
-
expect(hook.index(/^ensure/)).to be < hook.index('@video_recorder&.cleanup')
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
if automation == 'selenium'
|
|
72
|
-
context 'with trace recording' do
|
|
73
|
-
it 'requires trace_helper' do
|
|
74
|
-
expect(env).to include("require_relative '../../helpers/trace_helper'")
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'counts attempts per scenario location and starts the trace recorder after the video recorder' do
|
|
78
|
-
before_hook = env[/^Before do.*?^end$/m]
|
|
79
|
-
expect(env).to match(/^TRACE_ATTEMPTS = Hash\.new\(0\) unless defined\?\(TRACE_ATTEMPTS\)$/)
|
|
80
|
-
expect(before_hook).to include('TRACE_ATTEMPTS[scenario.location.to_s] += 1', '@trace_recorder = TraceHelper.recorder_for(driver)')
|
|
81
|
-
expect(before_hook).to match(/^Before do \|scenario\|$/)
|
|
82
|
-
expect(before_hook.index('@video_recorder.start')).to be < before_hook.index('@trace_recorder = TraceHelper')
|
|
83
|
-
expect(before_hook).to match(/if defined\?\(TraceHelper\)\n(.*\n)*.*@trace_recorder = TraceHelper/)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it 'stops with keep: TraceHelper.keep_all? || scenario.failed? before the video, attaches it and cleans up before quitting' do
|
|
87
|
-
expect(hook).to include('TraceHelper.keep_all? || scenario.failed?', 'error: scenario.exception', 'attempt: @trace_attempt')
|
|
88
|
-
expect(hook).to include("RaiderReporter.attach('trace', trace_path, type: :trace, attempt: @trace_attempt) if trace_path")
|
|
89
|
-
order = [hook.index('@trace_recorder&.stop'), hook.index('@video_recorder&.stop'), hook.index("RaiderReporter.attach('trace'"),
|
|
90
|
-
hook.index(/^ensure/), hook.index('@trace_recorder&.cleanup'), hook.index('@video_recorder&.cleanup'), hook.index('driver.quit')]
|
|
91
|
-
expect(order).to all(be_an(Integer)).and eq(order.compact.sort)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
it 'survives a Before that raised before the trace init, and a failing plugin setup or handler' do
|
|
95
|
-
expect(hook).to include('@trace_test&.merge(')
|
|
96
|
-
expect(hook).not_to include('@trace_test.merge(')
|
|
97
|
-
plugin = env[/^InstallPlugin do.*?^end$/m]
|
|
98
|
-
expect(plugin.scan('rescue StandardError => e').size).to eq(3)
|
|
99
|
-
expect(plugin.index('AstLookup.new')).to be > plugin.index("begin\n")
|
|
100
|
-
expect(plugin).to include('TraceHelper.warn_once("Gherkin step groups unavailable')
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
it 'turns tracing off with TraceHelper.disable! when a step group handler raises' do
|
|
104
|
-
plugin = env[/^InstallPlugin do.*?^end$/m]
|
|
105
|
-
expect(plugin.scan(/TraceHelper\.disable!\("step groups failed: \#\{e\.message\}"\) if defined\?\(TraceHelper\)/).size).to eq(2)
|
|
106
|
-
expect(plugin).not_to include('tracing disabled')
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it 'records each Gherkin step as a group through the InstallPlugin step events, skipping hooks' do
|
|
110
|
-
plugin = env[/^InstallPlugin do.*?^end$/m]
|
|
111
|
-
expect(plugin).to include('config.on_event(:test_step_started)', 'config.on_event(:test_step_finished)', 'next if event.test_step.hook?')
|
|
112
|
-
expect(plugin).to include('TraceHelper.active_recorder&.step_started', 'TraceHelper.active_recorder&.step_finished')
|
|
113
|
-
expect(plugin).to include('defined?(TraceHelper)')
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
else
|
|
117
|
-
it 'has no trace wiring' do
|
|
118
|
-
expect(env).not_to match(/trace/i)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it 'does not generate the allure helper' do
|
|
123
|
-
expect(File).not_to exist(File.join(project_name, 'helpers/allure_helper.rb'))
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it 'does not mention Allure in any generated file' do
|
|
127
|
-
files = Dir.glob("#{project_name}/**/*", File::FNM_DOTMATCH).select { |f| File.file?(f) }
|
|
128
|
-
expect(files.select { |f| File.read(f).match?(/allure/i) }).to be_empty
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it 'does not create an allure-results folder' do
|
|
132
|
-
expect(File).not_to exist(File.join(project_name, 'allure-results'))
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
describe 'Cucumber login reuse wiring' do
|
|
139
|
-
{ 'selenium' => 'driver', 'watir' => 'browser.driver' }.each do |automation, target|
|
|
140
|
-
context "with cucumber and #{automation}" do
|
|
141
|
-
let(:env) { read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'features/support/env.rb') }
|
|
142
|
-
|
|
143
|
-
it 'requires session_state' do
|
|
144
|
-
expect(env).to include("require_relative '../../helpers/session_state'")
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
it "reuses the saved login in Before('@logged_in'), defined after the plain Before" do
|
|
148
|
-
expect(env).to include("Before('@logged_in') do", "SessionState.new(#{target}).reuse(",
|
|
149
|
-
"UserFactory.for('registered user')")
|
|
150
|
-
expect(env.index("Before('@logged_in')")).to be > env.index(/^Before do/)
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
%w[android ios cross_platform].each do |automation|
|
|
156
|
-
it "does not mention session_state with cucumber and #{automation}" do
|
|
157
|
-
env = read_generated("#{FrameworkIndex::CUCUMBER}_#{automation}", 'features/support/env.rb')
|
|
158
|
-
expect(env).not_to include('session_state')
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative '../../../lib/generators/cucumber/cucumber_generator'
|
|
4
|
-
require_relative '../spec_helper'
|
|
5
|
-
|
|
6
|
-
describe CucumberGenerator do
|
|
7
|
-
shared_examples 'creates cucumber files' do |project_name, file_name|
|
|
8
|
-
it 'creates a feature file' do
|
|
9
|
-
expect(File).to exist("#{project_name}/features/#{file_name}.feature")
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it 'creates a step definitions file' do
|
|
13
|
-
expect(File).to exist("#{project_name}/features/step_definitions/#{file_name}_steps.rb")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'creates an env file' do
|
|
17
|
-
expect(File).to exist("#{project_name}/features/support/env.rb")
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'creates an cucumber.yml file' do
|
|
21
|
-
expect(File).to exist("#{project_name}/cucumber.yml")
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it 'does not create a spec file' do
|
|
25
|
-
expect(File).not_to exist("#{project_name}/spec/home_spec.rb")
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
shared_examples 'creates factories for web projects' do |project_name|
|
|
30
|
-
it 'creates an data file' do
|
|
31
|
-
expect(File).to exist("#{project_name}/models/data/users.yml")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'creates a model factory' do
|
|
35
|
-
expect(File).to exist("#{project_name}/models/model_factory.rb")
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it 'creates a user factory' do
|
|
39
|
-
expect(File).to exist("#{project_name}/models/user_factory.rb")
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
context 'with cucumber and appium android' do
|
|
44
|
-
include_examples 'creates cucumber files', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::ANDROID}", 'home'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
context 'with cucumber and appium ios' do
|
|
48
|
-
include_examples 'creates cucumber files', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::IOS}", 'home'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
context 'with cucumber and appium cross platform' do
|
|
52
|
-
include_examples 'creates cucumber files', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::CROSS_PLATFORM}", 'home'
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context 'with cucumber and selenium' do
|
|
56
|
-
include_examples 'creates cucumber files', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}", 'login'
|
|
57
|
-
include_examples 'creates factories for web projects', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::SELENIUM}", 'login'
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
context 'with cucumber and watir' do
|
|
61
|
-
include_examples 'creates cucumber files', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}", 'login'
|
|
62
|
-
include_examples 'creates factories for web projects', "#{FrameworkIndex::CUCUMBER}_#{AutomationIndex::WATIR}", 'login'
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
describe 'without example tests' do
|
|
66
|
-
%w[selenium ios cross_platform].each do |automation|
|
|
67
|
-
context "with cucumber and #{automation}" do
|
|
68
|
-
let(:name) { ensure_project(framework: 'cucumber', automation:, examples: false) }
|
|
69
|
-
|
|
70
|
-
it 'creates no feature files' do
|
|
71
|
-
expect(Dir.glob("#{name}/features/**/*.feature")).to be_empty
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
it 'keeps an empty step_definitions folder' do
|
|
75
|
-
expect(Dir.children("#{name}/features/step_definitions")).to eq(['.keep'])
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
it 'creates the support files' do
|
|
79
|
-
expect(Dir.children("#{name}/features/support")).to contain_exactly('env.rb', 'world.rb')
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it 'creates the cucumber.yml file' do
|
|
83
|
-
expect(File).to exist("#{name}/cucumber.yml")
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it 'creates no user factory' do
|
|
87
|
-
expect(File).not_to exist("#{name}/models/user_factory.rb")
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it 'creates no accessibility example' do
|
|
93
|
-
InvokeGenerators.generate_framework(framework: 'cucumber', automation: 'selenium', name: 'skeleton_axe_cucumber',
|
|
94
|
-
examples: false, accessibility: true)
|
|
95
|
-
expect(Dir.glob('skeleton_axe_cucumber/features/**/accessibility*')).to be_empty
|
|
96
|
-
ensure
|
|
97
|
-
FileUtils.rm_rf('skeleton_axe_cucumber')
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'wait_helper_support'
|
|
4
|
-
|
|
5
|
-
# The mobile render loads into App, so its WaitHelper and RaiderElement never meet the web
|
|
6
|
-
# render's top-level ones when both spec files run in one process.
|
|
7
|
-
module WaitHelperMobileSpec
|
|
8
|
-
module App; end
|
|
9
|
-
WaitHelperSpec.load_templates(mobile: true, into: App)
|
|
10
|
-
|
|
11
|
-
class Page
|
|
12
|
-
include App::WaitHelper
|
|
13
|
-
|
|
14
|
-
attr_reader :driver
|
|
15
|
-
|
|
16
|
-
def initialize(driver)
|
|
17
|
-
@driver = driver
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
RSpec.describe 'WaitHelper on mobile' do
|
|
22
|
-
let(:driver) { WaitHelperSpec::FakeDriver.new(device: :ios) }
|
|
23
|
-
let(:android) { WaitHelperSpec::FakeDriver.new(device: :android) }
|
|
24
|
-
let(:page) { Page.new(driver) }
|
|
25
|
-
let(:per_os) { { ios: { accessibility_id: 'ios-card' }, android: { accessibility_id: 'android-card' } } }
|
|
26
|
-
|
|
27
|
-
def element(**state) = WaitHelperSpec::FakeElement.new(**state)
|
|
28
|
-
def clock = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
29
|
-
def screen_area = { left: 0, top: 20, width: 390, height: 800 }
|
|
30
|
-
|
|
31
|
-
describe '#tap and #click' do
|
|
32
|
-
it 'click once the element is visible, enabled and stable' do
|
|
33
|
-
%i[tap click].each do |name|
|
|
34
|
-
target = element(rects: [[0, 0, 10, 10], [5, 5, 10, 10], [5, 5, 10, 10]])
|
|
35
|
-
driver.script({ accessibility_id: name.to_s }, nil, element(displayed: false), element(enabled: false), target)
|
|
36
|
-
expect(page.public_send(name, { accessibility_id: name.to_s }, timeout: 2)).to eq(target)
|
|
37
|
-
expect(target.log).to eq([[:click]])
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
describe 'tap with a block' do
|
|
43
|
-
it 'is Object#tap on a RaiderElement: yields and returns the wrapper without clicking' do
|
|
44
|
-
card = element
|
|
45
|
-
driver.script({ accessibility_id: 'card' }, card)
|
|
46
|
-
wrapper = page.find_element(accessibility_id: 'card')
|
|
47
|
-
seen = nil
|
|
48
|
-
expect(wrapper.tap { |yielded| seen = yielded }).to be(wrapper)
|
|
49
|
-
expect([seen, card.log]).to eq([wrapper, []])
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it 'is Object#tap on the mixin: yields self without looking anything up' do
|
|
53
|
-
seen = nil
|
|
54
|
-
expect(page.tap { |yielded| seen = yielded }).to be(page)
|
|
55
|
-
expect(page.tap(&:driver)).to be(page)
|
|
56
|
-
expect([seen, driver.finds, driver.scripts]).to eq([page, [], []])
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it 'still clicks without a block' do
|
|
60
|
-
card = element
|
|
61
|
-
driver.script({ id: 'x' }, card)
|
|
62
|
-
page.tap({ id: 'x' }, timeout: 1)
|
|
63
|
-
page.tap(id: 'x')
|
|
64
|
-
page.find_element(id: 'x').tap
|
|
65
|
-
expect(card.log).to eq([[:click]] * 3)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
describe '#swipe' do
|
|
70
|
-
it 'uses mobile: swipe on iOS' do
|
|
71
|
-
card = element
|
|
72
|
-
driver.script({ accessibility_id: 'card' }, card)
|
|
73
|
-
expect(page.swipe('left', { accessibility_id: 'card' }, timeout: 1)).to eq(card)
|
|
74
|
-
expect(driver.scripts).to eq([['mobile: swipe', { direction: 'left', element: card.id }]])
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it 'uses mobile: swipeGesture on Android' do
|
|
78
|
-
card = element
|
|
79
|
-
android.script({ accessibility_id: 'card' }, card)
|
|
80
|
-
Page.new(android).swipe('left', { accessibility_id: 'card' }, timeout: 1)
|
|
81
|
-
expect(android.scripts)
|
|
82
|
-
.to eq([['mobile: swipeGesture', { elementId: card.id, direction: 'left', percent: 0.75 }]])
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it 'waits for the element to be visible first' do
|
|
86
|
-
card = element
|
|
87
|
-
driver.script({ accessibility_id: 'card' }, nil, element(displayed: false), card)
|
|
88
|
-
page.swipe('up', { accessibility_id: 'card' }, timeout: 1)
|
|
89
|
-
expect([driver.finds.size, driver.scripts.size]).to eq([3, 1])
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it 'swipes the whole screen without a locator' do
|
|
93
|
-
expect(page.swipe('up')).to be_nil
|
|
94
|
-
Page.new(android).swipe('up')
|
|
95
|
-
expect(driver.scripts).to eq([['mobile: swipe', { direction: 'up' }]])
|
|
96
|
-
expect(android.scripts).to eq([['mobile: swipeGesture', { **screen_area, direction: 'up', percent: 0.75 }]])
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it 'rejects a direction other than up, down, left or right' do
|
|
100
|
-
expect { page.swipe('sideways') }.to raise_error(ArgumentError, /up, down, left or right/)
|
|
101
|
-
expect(driver.scripts).to be_empty
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
describe '#scroll' do
|
|
106
|
-
it 'scrolls the screen without a locator' do
|
|
107
|
-
page.scroll('down')
|
|
108
|
-
Page.new(android).scroll('down')
|
|
109
|
-
expect(driver.scripts).to eq([['mobile: scroll', { direction: 'down' }]])
|
|
110
|
-
expect(android.scripts).to eq([['mobile: scrollGesture', { **screen_area, direction: 'down', percent: 0.75 }]])
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it 'scrolls a container' do
|
|
114
|
-
list = element
|
|
115
|
-
android.script({ id: 'list' }, list)
|
|
116
|
-
Page.new(android).scroll('up', { id: 'list' }, timeout: 1)
|
|
117
|
-
expect(android.scripts).to eq([['mobile: scrollGesture', { elementId: list.id, direction: 'up', percent: 0.75 }]])
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
describe 'an unknown device' do
|
|
122
|
-
it 'raises NotImplementedError naming it, before waiting' do
|
|
123
|
-
windows = WaitHelperSpec::FakeDriver.new(device: :windows)
|
|
124
|
-
started = clock
|
|
125
|
-
expect { Page.new(windows).swipe('left', { id: 'never' }, timeout: 2) }
|
|
126
|
-
.to raise_error(NotImplementedError, /windows/)
|
|
127
|
-
expect { Page.new(windows).scroll('down') }.to raise_error(NotImplementedError, /windows/)
|
|
128
|
-
expect(clock - started).to be < 0.5
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
describe '#scroll_to' do
|
|
133
|
-
it 'returns a RaiderElement once the element turns visible after 2 scrolls' do
|
|
134
|
-
footer = element
|
|
135
|
-
driver.script({ accessibility_id: 'footer' }, nil, element(displayed: false), footer)
|
|
136
|
-
found = page.scroll_to({ accessibility_id: 'footer' }, timeout: 2)
|
|
137
|
-
expect(found).to be_a(App::RaiderElement).and eq(footer)
|
|
138
|
-
expect(driver.scripts).to eq([['mobile: scroll', { direction: 'down' }]] * 2)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
it 'scrolls in the given direction' do
|
|
142
|
-
driver.script({ accessibility_id: 'header' }, nil, element)
|
|
143
|
-
page.scroll_to({ accessibility_id: 'header' }, direction: 'up', timeout: 2)
|
|
144
|
-
expect(driver.scripts).to eq([['mobile: scroll', { direction: 'up' }]])
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
it 'stops after max_scrolls scrolls and says so' do
|
|
148
|
-
started = clock
|
|
149
|
-
expect { page.scroll_to({ accessibility_id: 'footer' }, max_scrolls: 3, timeout: 5) }
|
|
150
|
-
.to raise_error(App::WaitHelper::TimeoutError) { |error|
|
|
151
|
-
expect(error.message).to include('to be visible').and include('after 3 scrolls')
|
|
152
|
-
}
|
|
153
|
-
expect(driver.scripts.size).to eq(3)
|
|
154
|
-
expect(driver.finds.size).to eq(4)
|
|
155
|
-
expect(clock - started).to be < 2
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
it 'also stops at the timeout, naming the scrolls so far' do
|
|
159
|
-
expect { page.scroll_to({ accessibility_id: 'footer' }, timeout: 0) }
|
|
160
|
-
.to raise_error(App::WaitHelper::TimeoutError, /after 0 scrolls/)
|
|
161
|
-
expect(driver.scripts).to be_empty
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
describe 'per-OS locators' do
|
|
166
|
-
it 'resolve on tap and swipe' do
|
|
167
|
-
card = element
|
|
168
|
-
android.script({ accessibility_id: 'android-card' }, card)
|
|
169
|
-
mobile = Page.new(android)
|
|
170
|
-
mobile.tap(per_os, timeout: 1)
|
|
171
|
-
mobile.swipe('right', per_os, timeout: 1)
|
|
172
|
-
expect(android.finds.uniq).to eq([{ accessibility_id: 'android-card' }])
|
|
173
|
-
expect([card.log, android.scripts.size]).to eq([[[:click]], 1])
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
it 'resolve on a nested find_element' do
|
|
177
|
-
row = element
|
|
178
|
-
list = element.script({ accessibility_id: 'ios-row' }, row)
|
|
179
|
-
driver.script({ accessibility_id: 'ios-card' }, list)
|
|
180
|
-
found = page.find_element(per_os).find_element({ ios: { accessibility_id: 'ios-row' }, android: { id: 'row' } })
|
|
181
|
-
expect(found).to eq(row)
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
describe 'RaiderElement' do
|
|
186
|
-
it 'has the mobile set without the locator' do
|
|
187
|
-
card = element
|
|
188
|
-
driver.script({ accessibility_id: 'card' }, card)
|
|
189
|
-
wrapper = page.find_element(accessibility_id: 'card')
|
|
190
|
-
expect(wrapper.tap.swipe('left').scroll('down').scroll_to).to be(wrapper)
|
|
191
|
-
expect(card.log).to eq([[:click]])
|
|
192
|
-
expect(driver.scripts).to eq([['mobile: swipe', { direction: 'left', element: card.id }],
|
|
193
|
-
['mobile: scroll', { direction: 'down', element: card.id }]])
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
it 'adds exactly the planned public methods' do
|
|
197
|
-
expect(App::RaiderElement.public_instance_methods(false).sort)
|
|
198
|
-
.to eq(%i[== attribute clear click displayed? enabled? eql? find_element find_elements hash native scroll
|
|
199
|
-
scroll_to selected? send_keys swipe tap text])
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
describe 'the choke point' do
|
|
204
|
-
let(:actions) { [] }
|
|
205
|
-
|
|
206
|
-
before do
|
|
207
|
-
driver.script({ id: 'x' }, element.script({ css: 'y' }, element).script_many({ css: 'y' }, [element]))
|
|
208
|
-
allow_any_instance_of(App::WaitHelper::Waiter).to receive(:perform_action).and_wrap_original do |original, *args, **options, &block|
|
|
209
|
-
actions << args.first
|
|
210
|
-
original.call(*args, **options, &block)
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def calls(locator)
|
|
215
|
-
{ find_element: [locator], find_elements: [locator], click: [locator], tap: [locator], clear: [locator],
|
|
216
|
-
text: [locator], displayed?: [locator], enabled?: [locator], selected?: [locator],
|
|
217
|
-
send_keys: [locator, 'a'], attribute: [locator, 'name'], swipe: ['left', locator],
|
|
218
|
-
scroll: ['down', locator], scroll_to: [locator] }
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
it 'is called once per mixin method, with the method name' do
|
|
222
|
-
calls({ id: 'x' }).each do |name, args|
|
|
223
|
-
actions.clear
|
|
224
|
-
page.public_send(name, *args, timeout: 1)
|
|
225
|
-
expect(actions).to eq([name])
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
it 'is called once for a whole-screen gesture' do
|
|
230
|
-
%i[swipe scroll].each do |name|
|
|
231
|
-
actions.clear
|
|
232
|
-
page.public_send(name, 'up')
|
|
233
|
-
expect(actions).to eq([name])
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it 'is called once per wrapper method, with the method name' do
|
|
238
|
-
wrapper = page.find_element(id: 'x')
|
|
239
|
-
calls({ css: 'y' }).each do |name, args|
|
|
240
|
-
args = args.reject { |arg| arg.is_a?(Hash) } unless %i[find_element find_elements].include?(name)
|
|
241
|
-
actions.clear
|
|
242
|
-
wrapper.public_send(name, *args, timeout: 1)
|
|
243
|
-
expect(actions).to eq([name])
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
describe 'footprint' do
|
|
249
|
-
it 'adds exactly the mobile API, with no private methods and nothing named wait' do
|
|
250
|
-
expect(App::WaitHelper.public_instance_methods(false).sort)
|
|
251
|
-
.to eq(%i[attribute clear click displayed? enabled? eventually find_element find_elements scroll scroll_to
|
|
252
|
-
selected? send_keys swipe tap text])
|
|
253
|
-
expect(App::WaitHelper.private_instance_methods(false)).to be_empty
|
|
254
|
-
expect(page.respond_to?(:wait, true)).to be(false)
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
describe '#eventually' do
|
|
259
|
-
it 'retries the block as on web' do
|
|
260
|
-
tries = 0
|
|
261
|
-
expect(page.eventually(timeout: 1) { expect(tries += 1).to eq(2) }).to be(true)
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
it 'retries a nested timeout: until its own deadline, as on web' do
|
|
265
|
-
started = clock
|
|
266
|
-
expect { page.eventually(timeout: 0.6) { page.text({ accessibility_id: 'never' }, timeout: 0.2) } }
|
|
267
|
-
.to raise_error(App::WaitHelper::TimeoutError, /\A\(still failing after 0.6s\)/)
|
|
268
|
-
expect(clock - started).to be_between(0.5, 1.0)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
it 'raises at once for a stale find_elements member used as a parent' do
|
|
272
|
-
row = element.script({ accessibility_id: 'cell' }, element)
|
|
273
|
-
driver.script_many({ accessibility_id: 'row' }, [row])
|
|
274
|
-
member = page.find_elements(accessibility_id: 'row').first
|
|
275
|
-
row.go_stale
|
|
276
|
-
expect { member.find_element(accessibility_id: 'cell', timeout: 2) }
|
|
277
|
-
.to raise_error(Selenium::WebDriver::Error::StaleElementReferenceError, /find_elements again/)
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
end
|
|
281
|
-
end
|