-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a spike of a couple hours' work to show what E2E tests with Capybara could look like. This implements "Task 1" of the tech spec discussed on 9/27. These tests won't run during CI, but maybe they will be useful in our manual testing. Future plans are to stub out Pinwheel and then enable these in CI.
- Loading branch information
Showing
9 changed files
with
221 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
require "rails_helper" | ||
|
||
RSpec.describe "e2e CBV flow test", type: :feature, js: true do | ||
include E2eTestHelpers | ||
include_context "with_ngrok_tunnel" | ||
|
||
let(:cbv_flow_invitation) { create(:cbv_flow_invitation) } | ||
|
||
before(:all, js: true) do | ||
unless ENV.fetch("PINWHEEL_API_TOKEN_SANDBOX", "").length == 64 | ||
raise "You need to set a PINWHEEL_API_TOKEN_SANDBOX in .env.test.local in order for this test to succeed" | ||
end | ||
unless ENV.fetch("USER", "").length > 0 | ||
raise "You need to set a USER environment variable" | ||
end | ||
|
||
# TODO: Remove this when we stub out Pinwheel usage: | ||
# (We will have to allow access to the capybara server URL.) | ||
WebMock.allow_net_connect! | ||
|
||
# Register Ngrok with Pinwheel | ||
capybara_server_url = URI(page.server_url) | ||
@ngrok.start_tunnel(capybara_server_url.port) | ||
puts "Found ngrok tunnel at #{@ngrok.tunnel_url}!" | ||
@subscription_id = PinwheelWebhookManager.new.create_subscription_if_necessary( | ||
@ngrok.tunnel_url, | ||
ENV["USER"] | ||
) | ||
end | ||
|
||
after(:all, js: true) do | ||
if @subscription_id | ||
puts "[PINWHEEL] Deleting webhook subscription id: #{@subscription_id}" | ||
PinwheelService.new("sandbox").delete_webhook_subscription(@subscription_id) | ||
end | ||
|
||
# TODO: Remove these when we stub out Pinwheel usage: | ||
page.quit | ||
WebMock.disable_net_connect! | ||
end | ||
|
||
shared_examples "proceeding through the flow normally" do | ||
it "completes the flow" do | ||
# /cbv/entry | ||
visit URI(cbv_flow_invitation.to_url).request_uri | ||
verify_page(page, title: I18n.t("cbv.entries.show.header.default", agency_acronym: "CBV")) | ||
click_button I18n.t("cbv.entries.show.get_started") | ||
|
||
# /cbv/agreement | ||
verify_page(page, title: I18n.t("cbv.agreements.show.header")) | ||
find("label", text: I18n.t("cbv.agreements.show.checkbox.default", agency_full_name: I18n.t("shared.agency_full_name.sandbox"))).click | ||
click_button I18n.t("cbv.agreements.show.continue") | ||
|
||
# /cbv/employer_search | ||
verify_page(page, title: I18n.t("cbv.employer_searches.show.header")) | ||
fill_in name: "query", with: "foo" | ||
click_button I18n.t("cbv.employer_searches.show.search") | ||
expect(page).to have_content("McKee Foods") | ||
find("div.usa-card__container", text: "McKee Foods").click_button(I18n.t("cbv.employer_searches.show.select")) | ||
|
||
# Pinwheel modal | ||
pinwheel_modal = page.find("iframe.pinwheel-modal-show") | ||
page.within_frame(pinwheel_modal) do | ||
debugger | ||
if I18n.locale == :en | ||
fill_in "Username", with: "user_good", wait: 10 | ||
fill_in "Workday Password", with: "pass_good" | ||
click_button "Continue" | ||
elsif I18n.locale == :es | ||
fill_in "Nombre de usuario", with: "user_good", wait: 10 | ||
fill_in "Contraseña de Workday", with: "pass_good" | ||
click_button "Continuar" | ||
else | ||
raise "Unknown locale: #{I18n.locale}" | ||
end | ||
end | ||
|
||
# /cbv/synchronizations | ||
verify_page(page, title: I18n.t("cbv.synchronizations.show.header"), wait: 15) | ||
|
||
# All the pinwheel webhooks occur here! | ||
|
||
# /cbv/payment_details | ||
verify_page(page, title: I18n.t("cbv.payment_details.show.header", employer_name: "Acme Corporation"), wait: 60) | ||
fill_in "cbv_flow[additional_information]", with: "Some kind of additional information" | ||
click_button I18n.t("cbv.payment_details.show.continue") | ||
|
||
# /cbv/add_job | ||
verify_page(page, title: I18n.t("cbv.add_jobs.show.header")) | ||
find("label", text: I18n.t("cbv.add_jobs.show.no_radio")).click | ||
click_button I18n.t("cbv.add_jobs.show.continue") | ||
|
||
# /cbv/summary | ||
verify_page(page, title: I18n.t("cbv.summaries.show.header")) | ||
find(:css, "label[for=cbv_flow_consent_to_authorized_use]").click | ||
click_button I18n.t("cbv.summaries.show.send_report", agency_acronym: "CBV") | ||
|
||
# TODO: Test PDF rendering by writing it to a file | ||
end | ||
end | ||
|
||
context "in english" do | ||
it_behaves_like "proceeding through the flow normally" | ||
end | ||
|
||
context "in spanish" do | ||
before do | ||
cbv_flow_invitation.update(language: "es") | ||
end | ||
|
||
around do |ex| | ||
I18n.with_locale("es", &ex) | ||
end | ||
|
||
it_behaves_like "proceeding through the flow normally" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
require "open3" | ||
|
||
# This shared context handles the lifecycle of an ngrok subprocess. | ||
# | ||
# To use it in your specs: | ||
# | ||
# include_context "with_ngrok_tunnel" | ||
# | ||
# and then in your before/after blocks: | ||
# | ||
# before(:all) do | ||
# @ngrok.start_tunnel(3000) # Create tunnel to port 3000 | ||
# | ||
# # Do something with the Ngrok tunnel | ||
# puts "Ngrok is running at #{@ngrok.tunnel_url}" | ||
# end | ||
RSpec.shared_context "with_ngrok_tunnel" do | ||
class NgrokManager | ||
def initialize | ||
@thread = nil | ||
@tunnel_url = nil | ||
end | ||
|
||
def start_tunnel(destination_port) | ||
@thread = Thread.new do |t| | ||
begin | ||
_stdin, stdout, _stderr, wait_thr = Open3.popen3("ngrok http #{destination_port} --log stdout") | ||
puts "[NGROK] Started with pid #{wait_thr.pid} to local port #{destination_port}" | ||
stdout.each_line do |log| | ||
if log.include?('msg="started tunnel"') | ||
@tunnel_url ||= log.match(/url=([^ ]+)/)[1].strip | ||
end | ||
end | ||
rescue => e | ||
puts "[NGROK] Fatal error: #{e}" | ||
ensure | ||
puts "[NGROK] Killing pid #{wait_thr.pid}" | ||
Process.kill("TERM", wait_thr.pid) if wait_thr.alive? | ||
end | ||
end | ||
end | ||
|
||
def tunnel_url | ||
Timeout.timeout(5) { sleep 0.1 while @tunnel_url.nil? } | ||
|
||
@tunnel_url | ||
rescue Timeout::Error => ex | ||
raise "[NGROK] Timed out waiting for ngrok to initialize. Make sure `ngrok http 3000 --log stdout` works locally?" | ||
end | ||
|
||
def kill | ||
@thread.kill if @thread | ||
end | ||
end | ||
|
||
before(:all) do | ||
@ngrok = NgrokManager.new | ||
end | ||
|
||
after(:all) do | ||
@ngrok.kill if @ngrok | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module E2eTestHelpers | ||
def verify_page(page, title:, wait: Capybara.default_max_wait_time) | ||
expect(page).to have_content(title, wait: wait) | ||
|
||
# Verify page has no missing translations | ||
Capybara.using_wait_time(0) do | ||
missing_translations = page.all("span", class: "translation_missing") | ||
raise(<<~ERROR) if missing_translations.any? | ||
E2E test failed on #{page.current_url}: | ||
#{missing_translations.map { |el| el["title"] }} | ||
ERROR | ||
end | ||
end | ||
end |