不可靠/不稳定的 Capybara/AngularJS 集成测试与计时问题

2024-05-11

如何使这些测试可靠地通过?

目前这些测试很不稳定。
有时他们会过去。有时他们会失败。
下面是演示此问题的设置、代码和输出。
克服这个问题的建议将不胜感激,我相信也会帮助许多其他人,所以请发表评论!

测试代码环境

  1. 轨道3.2
  2. RSpec 2.x
  3. 水豚
  4. 恶作剧鬼
  5. PhantomJS
  6. AngularJS
  7. 谷歌浏览器版本 47.0.2526.106(64 位)

从 Gemfile.lock 测试 Gem

capybara (2.1.0)
database_cleaner (0.7.1)
debug_inspector (0.0.2)
guard-bundler (0.1.3)
guard-livereload (1.2.0)
guard-rspec (2.1.2)
jasminerice (0.0.10)
pg (0.17.1)
phantomjs (2.1.1.0)
poltergeist (1.4.1)
protractor-rails (0.0.17)
pry (0.9.12)
rack (1.4.7)
rack-test (0.6.3)
rails (3.2.21)
rails-assets-angular (1.3.20)
rspec-rails (2.11.4)
simplecov (0.8.2)
sprockets (2.2.3)
zeus (0.13.3)
zeus-parallel_tests (0.2.1)

我尝试过的事情

  1. 确保我使用 Capybara 的等待 DSL 匹配器
  2. 确保我的数据库清理器设置正确
  3. 测试每个页面项目,假设它可能不在页面上并且仍然可以加载
  4. 缩小不一致的测试范围
  5. 单独运行不一致的测试
  6. 识别触发不一致测试结果的 Capybara DSL 代码。

    • 即创建一条新记录并假设页面已重定向并且该记录位于页面 click_on 上

    or

    • .click 不一致“工作”
  7. 将 Capybara 升级到最新版本(在单独的分支中)
  8. 将 Poltergeist 和 RSpec 升级到最新版本(在单独的分支中,仍在处理此问题)

我使用的资源

[1] 水豚 DSL https://github.com/jnicklas/capybara#the-dsl
[2] Capybara、PhantomJs、Poltergeist 和 Rspec 提示 http://www.railsonmaui.com/tips/rails/capybara-phantomjs-poltergeist-rspec-rails-tips.html
还有很多...

测试是如何进行的

rspec spec/integration/costings/show_costing_spec.rb --format documentation

测试代码

show_costing_spec.rb
require "spec_helper"

RSpec.describe "Show a new costing in the listing," do

  before :each do
    admin_sign_in
    create_costing("test1")
  end

  it "shows the costing after creation" do
    within "#costings_table" do
      expect(page).to have_css("#name", text: "test1")
    end
  end

  it "shows the details of the new costing after creation" do
    expect(page).to have_content("Costings")
    within "#costings_table" do
      expect(page).to have_content("test1")
      all("#show").last.click
    end

    expect(page).to have_content("Costing Details")
    expect(page).to have_css("#name", text: "test1")
  end
end  
spec_helper.rb
# This file is copied to spec/ when you run 'rails generate r spec:install'  
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
# Add library functions here so we can test them.
require File.expand_path(File.dirname(__FILE__) + "/../lib/general")
require 'rspec/rails'
require 'rspec/autorun'

# Integration Testing
require 'capybara/poltergeist'
Capybara.register_driver :poltergeist_debug do |app|
 Capybara::Poltergeist::Driver.new(app, :inspector => true)  
end
Capybara.javascript_driver = :poltergeist_debug
Capybara.default_driver = :poltergeist_debug

# Capybara Integration Test Helpers
def admin_sign_in
  visit "/login"
  #Create staff member in database
  Staff.make!(:admin)
  #Log In
  fill_in "staff_username", with: "adminstaff"
  fill_in "staff_password", with: "password"
  click_button "login"
end

def create_costing(item)
  visit "/api#/costings"
  click_on "new_btn"
  within "#form_costing" do
    find("#name", match: :first).set("#{item}")
    find("#description", match: :first).set("test description")    
    find("#from_date", match: :first).set("15/02/2016")
    find("#cost_hourly_cents", match: :first).set("1.00")
    click_on "create_btn"
  end
end

RSpec.configure do |config|
  config.before(:suite) do
    # Requires supporting ruby files with custom matchers and macros, etc,
    # in spec/support/ and its subdirectories.
    require File.expand_path(File.dirname(__FILE__) + "/support/blueprints")
    Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
  end

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # Allow a 'focus' tag so that we can run just a few tests which we are currently working on
  config.treat_symbols_as_metadata_keys_with_true_values = true
  config.filter_run focus: true
  config.run_all_when_everything_filtered = true
  config.filter_run_excluding :slow unless ENV["SLOW_SPECS"]

  # Defer Garbage Collection
  config.before(:all) { DeferredGarbageCollection.start }
  config.after(:all)  { DeferredGarbageCollection.reconsider }

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false
  # config.infer_spec_type_from_file_location!

  # Configure Database Cleaner
  config.include Capybara::DSL
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end

检测结果

Test Run 1: Failing

运行选项: 包括 {:focus=>true} 排除 {:slow=>true}

所有的例子都被过滤掉了;忽略 {:focus=>true}

在列表中显示新的成本计算, 显示创建后的成本核算 显示创建后新成本核算的详细信息(失败 - 1)

失败:

1) 在列表中显示新的成本计算,
显示创建后新成本核算的详细信息
失败/错误:expect(page).to have_content("test1")
预期 #has_content?("test1") 返回 true,结果为 false
# ./spec/integration/costings/show_costing_spec.rb:20:in 块(3 个级别)中
# ./spec/integration/costings/show_costing_spec.rb:19:in 块(2 级)中

5.46秒完成 2个例子,1个失败

Test Run 2: Passing

运行选项: 包括 {:focus=>true} 排除 {:slow=>true}

所有的例子都被过滤掉了;忽略 {:focus=>true}

在列表中显示新的成本计算,
显示创建后的成本核算
显示创建后新成本核算的详细信息

3.57秒完成 2 个示例,0 次失败

Update 1

将测试gem升级到以下版本:
水豚 (2.6.2) 来自 (2.1.0)
来自 (0.7.1) 的数据库清理器 (1.5.1)
调试检查器 (0.0.2)
防护捆绑器 (0.1.3)
守卫-livereload (1.2.0)
防护规格 (2.1.2)
茉莉花 (0.0.10)
场均 (0.17.1)
phantomjs (2.1.1.0)
恶作剧鬼 (1.9.0) 来自 (1.4.1)
量角器导轨 (0.0.17)
从 (0.9.12) 撬出 (0.10.3)
机架 (1.4.7)
机架测试 (0.6.3)
导轨 (3.2.21)
轨道资产角度(1.4.9)来自(1.3.20)
rspec-rails (3.4.2) 来自 (2.11.4)
simplecov (0.8.2)
链轮 (2.2.3)
宙斯 (0.13.3)
zeus-parallel_tests (0.2.1)

Result 1

不幸的是,升级这些宝石似乎并没有产生什么影响,而且我的测试仍然不稳定。

Update 2

我实施了汤姆·沃波尔的建议。确保我的 admin_sign_in 等待 Sign_in 完成。

还按照汤姆的建议更新了我的database_cleaner设置。

Result 2

对于我的堆栈来说,这些更改似乎没有效果。

Note:如果不使用 AngularJS,我觉得这些改变会产生影响。谢谢汤姆的建议。

Update 3

我需要获得有关测试运行期间发生的情况的更多信息。网上有一些建议来记录、使用屏幕截图保存宝石等,但我不觉得这些是最省时的。我想指定测试在哪里暂停并查看变量和表单字段的内容。在浏览器中是理想的选择。

我用过什么
我使用“save_and_open_page”和“print page.html”进行调试。

我搬到了什么地方
当我运行 RSpec 3.4.2 时,我添加了一个调试帮助器方法:

Rails_helper.rb

def debugit
  puts current_url
  require 'pry'
  binding.pry
end

Result 3

URL 将打印在控制台中,并且测试将暂停。在此阶段,我将能够导航到 URL、登录、导航到测试页面并查看 Capybara 测试已完成的操作。

这使我能够确定问题的根源是在使用水豚的 fill_in DSL 进行测试时出现的。 在某些测试运行中,字段将被正确填充并且表单将被提交。 在另一种情况下,表单将被正确填写,但提交按钮会被点击得太快。这里的结果是创建了一条记录,但名称和描述的输入字段未保留。

Update 4

我发现因为我使用的是 AngularJS 输入表单和表格,所以 AngularJS 需要一点时间来绑定到输入字段。如果这次不允许,则不会保存输入数据。

Capybara提供了“within”、“find”等等待方法。我使用了这些,但它们对解决 AngularJS 绑定时间问题没有帮助。 我发现 ng-if 可以用来创建一个 if 语句来等待特定项目,该项目将表示 AngularJS 与表单字段的绑定完成。

所以我使用 Capybara 等待方法来等待我想要填充的字段,并使用 AngularJS 的 ng-if 在字段准备好之前不显示字段。

执行
索引.html.erb

<div  ng-if="tableParams.data">
  <table id="costings_table ng-table="tableParams" class="table">
    <td id="field1">{{table.field1}}</td>
    <td id="field2">{{table.field2}}</td>
  </table>
</div>

Result 4

测试终于通过了!然而,我拥有所有这些带有 xpath 的查找方法,确保等待特定且难以定位的项目...

Update 5

尽管在我的 gemfile 中我运行的是 gem phantomJS 版本 2.1.1,但我的命令行版本仅为 1.X。事实证明这意义重大。

我将命令行 phantomJS 版本更新为 2.1.1。同时,我确保所有输入框、按钮、表格、标题都有唯一的 ID。然后我能够删除所有 find(:xpath) 出现而不会破坏测试。

Result 5

这套测试现在一直可靠地通过!正是我想要的!是的!


立即跳出来的是你的admin_sign_in实际上并不等待登录完成。这意味着您致电create_costing如果您的浏览器中未设置会话 cookie,则可能会发生这种情况。你的最后一行admin_sign_in方法应该是这样的

expect(page).to have_text('You are signed in') # whatever message is shown upon sign in

or

expect(page).to have_current_path('/') # whatever path an admin is redirected to upon signing in

这将确保登录实际上已完成,因此会话 cookie 已在您的浏览器中设置。

另外,您的数据库清理器配置应该使用append_after块而不是after - 请参阅https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

不可靠/不稳定的 Capybara/AngularJS 集成测试与计时问题 的相关文章

随机推荐

  • Yii2 Composer 管理 Bower 和 Bower-vendor 中的包

    我已经使用 yii2 一段时间了 但我不知道如何管理我的包 在这方面我有两个问题 当我将包添加到 yii2 时 它会在vendor bower bower assets 中下载 当 yii2 发布包时 它会在vendor bower下查找资
  • 基础设施 - 同步和异步接口和实现? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 在实现库 基础设施时 并且该 API 的用户希望同步和异步使用代码 我读到混合同步和异步并不是一个好主意 例如 同步实现包括等待异步实现 显然
  • MySQL-分割字符串

    我的问题与这篇文章类似 MySQL 中的 反向 GROUP CONCAT https stackoverflow com questions 17308669 reverse group concat in mysql 然而 而不是反转gr
  • C - 获取外部IP地址

    我需要通过 C C 调用获取我的公共 IP 地址 我知道作为替代方案 我可以从 http whatismyip akamai com 等外部链接获取 我写了一个示例来获取外部IP地址 但我的程序没有返回外部 IP 地址 我正在获取内部 IP
  • 为什么代码分析不警告 NotImplementedException?

    我非常确定 Visual Studio Code Analysis 的早期版本会警告有关 NotImplementedException 的使用 即包含此异常的任何成员 throw new NotImplementedException 会
  • 进程名称长度的最大允许限制是多少?

    进程名称允许的最大长度是多少 我正在读取进程名称 proc pid stat文件 我想知道我需要的最大缓冲区 我很确定有一个可配置的限制 但就是找不到它在哪里 根据man 2 prctl http man7 org linux man pa
  • Ansible 测试变量以什么开头

    我需要能够安装 MySQL 库 Python 有 1 个用于 v2 的包和另一个用于 v3 的包 我需要能够告诉 Ansible 要安装哪个包 name Ensure MySQL python is installed pip name M
  • Java:将秒转换为分钟、小时和天[重复]

    这个问题在这里已经有答案了 任务是 输出应如下所示 最好回显输入 您输入了 500 000 秒 即 5 天 18 小时 53 分钟 20 秒 5天18 53 20小时 我该怎么做呢 最容易理解和做到的方法是什么 讲师还说 没有硬编码 我不太
  • IE9支持CSS线性渐变吗?

    有了 Chrome Safari 和 Firefox webkit gradient and moz linear gradient特性 我怎样才能用 IE9 做同样的事情呢 最好的跨浏览器解决方案是 background fff back
  • SSHKit::Runner::ExecuteError:以 root@co 身份执行时出现异常:Jenkins Job 的 shell 脚本中的用户 root@ 身份验证失败

    我正在尝试从 Jenkins Job 运行 cap 部署命令 它不断抛出以下错误 我也在部署服务器中添加了 ssh 密钥 我能够从配置 Jenkins 的服务器成功部署 但是当我运行该作业时 会引发身份验证错误 这对我来说真的很重要 有人可
  • 猫头鹰轮播,制作自定义导航

    所以我有一个包含三张图像的猫头鹰旋转木马 我还在左侧和右侧添加了自定义导航箭头 png 图像 然而 这些箭头目前是无用的 因为我找不到一种方法来真正让它们在我的猫头鹰旋转木马的图像之间切换 我无休止地寻找 找不到解决方案 有任何想法吗 您需
  • 如何在notepad++中格式化JSON

    我想在记事本 中格式化JSON字符串 请指导我该怎么做 我研究了这个解决方案记事本 JSON 格式 https stackoverflow com questions 1560464 how to reformat json in note
  • 如何制作 SagePay BuyNow 按钮?

    通过 PayPal 我可以非常轻松地创建一个 BuyNow 按钮 其中包含我的商家信息 价格 税金 运费等 这在 SagePay 中可行吗 所需的系统称为 SagePay Form 与 PayPal 的 BuyNow 按钮 PDT 流程相似
  • 如何在控制台程序中获取鼠标位置?

    如何在 Windows 控制台程序中用 C 获取鼠标单击位置 点击时返回鼠标位置的变量 我想用简单的文本命令绘制一个菜单 这样当有人点击时 游戏就会注册它并知道位置 我知道如何做我需要做的一切 除了单击时获取鼠标位置 您需要使用 Conso
  • 什么是欣德利米尔纳?

    我遇到过这个词欣德利 米尔纳 我不确定是否理解它的意思 我已阅读以下帖子 史蒂夫 叶格 动态语言的反击 http steve yegge blogspot com 2008 05 dynamic languages strike back
  • 如何在Python中显示坐标网格线的变换?

    假设我有常规的笛卡尔坐标系 x y 并且我考虑一个矩形网格区域 D 分成小方块 我想看看域 D 如何在 Python 中的坐标变换 T x y gt u x y v x y 下映射 我正在寻找这样的东西 See here https mat
  • Javascript 最佳实践,为什么使用逗号来链接函数/变量声明?

    我一直在为 jQuery jQueryLog 开发一个插件 以允许调试链选择器和返回值 如果你想检查一下 你可以这样做here http www jquerylog com 这已经是第二个版本了 第一个版本实际上是经过编辑的 jQuery
  • Pandas:合并多个数据框并控制列名称?

    我想将九个 Pandas 数据帧合并到一个数据帧中 对两列进行联接 控制列名称 这可能吗 我有九个数据集 它们都有以下列 org name items spend 我想将它们加入到具有以下列的单个数据框中 org name items df
  • 调用我的过程时参数数量或类型错误

    您好 我编写了这段代码来创建一个过程 根据 if 条件返回布尔值 但是当我执行它时 我收到此错误 ORA 06550 line 1 column 7 PLS 00306 wrong number or types of arguments
  • 不可靠/不稳定的 Capybara/AngularJS 集成测试与计时问题

    如何使这些测试可靠地通过 目前这些测试很不稳定 有时他们会过去 有时他们会失败 下面是演示此问题的设置 代码和输出 克服这个问题的建议将不胜感激 我相信也会帮助许多其他人 所以请发表评论 测试代码环境 轨道3 2 RSpec 2 x 水豚