Last active
February 15, 2024 23:06
-
-
Save seanpdoyle/61ff045986e3ad2f0beee19cc2d0fa23 to your computer and use it in GitHub Desktop.
Add a `binding.irb` to the test, then execute `ruby application.rb`
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
require "bundler/inline" | |
gemfile(true) do | |
source "https://rubygems.org" | |
git_source(:github) { |repo| "https://github.com/#{repo}.git" } | |
gem "rails" | |
gem "sqlite3" | |
gem "capybara" | |
gem "selenium-webdriver" | |
end | |
require "rails/all" | |
class App < Rails::Application | |
config.load_defaults Rails::VERSION::STRING.to_f | |
config.root = __dir__ | |
config.hosts << "example.org" | |
config.eager_load = false | |
config.session_store :cookie_store, key: "cookie_store_key" | |
config.secret_key_base = "secret_key_base" | |
Rails.logger = config.logger = Logger.new($stdout) | |
routes.append do | |
root to: "timers#show" | |
end | |
end | |
class TimersController < ActionController::Base | |
def show | |
@timer = Time.parse(time_params) | |
render inline: DATA.read | |
end | |
private | |
def time_params | |
params.fetch(:expires_at, 10.minutes.from_now.iso8601) | |
end | |
end | |
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase | |
driven_by :selenium, using: :chrome, screen_size: [1400, 1400] | |
Capybara.server = :webrick | |
def travel_to(date_or_time, ...) | |
travel_browser_to date_or_time | |
super | |
end | |
def travel_back(...) | |
super | |
travel_browser_to Time.current | |
end | |
def travel_browser_to(date_or_time) | |
execute_script <<~JS, date_or_time | |
if (typeof window.travelTo === "function") travelTo(arguments[0]) | |
JS | |
end | |
end | |
ENV["DATABASE_URL"] = "sqlite3::memory:" | |
ENV["RAILS_ENV"] ||= "test" | |
Rails.application.initialize! | |
require "rails/test_help" | |
class TimerSystemTest < ApplicationSystemTestCase | |
test "timer ticks down" do | |
freeze_time do | |
visit root_path | |
assert_css "h1", text: "Ticking" | |
assert_css "time", text: "10:00" | |
travel 5.minutes | |
assert_css "h1", text: "Ticking" | |
assert_css "time", text: "05:00" | |
travel 5.minutes | |
assert_css "h1", text: "Expired" | |
assert_css "time", text: "00:00" | |
travel 5.minutes | |
assert_css "h1", text: "Expired" | |
assert_css "time", text: "00:00" | |
end | |
end | |
end | |
__END__ | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Timer Example</title> | |
<meta name="viewport" content="width=device-width,initial-scale=1"> | |
<%= csrf_meta_tags %> | |
<%= csp_meta_tag %> | |
<script type="importmap"> | |
{ | |
"imports": { | |
"@hotwired/stimulus": "https://ga.jspm.io/npm:@hotwired/stimulus@3.2.2/dist/stimulus.js", | |
"moment": "https://ga.jspm.io/npm:moment@2.30.1/moment.js", | |
"moment-duration-format": "https://ga.jspm.io/npm:moment-duration-format@2.3.2/lib/moment-duration-format.js", | |
"timemachine": "https://ga.jspm.io/npm:timemachine@0.3.2/timemachine.js" | |
} | |
} | |
</script> | |
<script type="module"> | |
import { Application, Controller } from "@hotwired/stimulus" | |
import moment from "moment" | |
import "moment-duration-format" | |
const application = Application.start() | |
application.register("timer", class extends Controller { | |
static values = { expired: Boolean } | |
connect() { | |
this.#start() | |
} | |
disconnect() { | |
this.#stop() | |
} | |
#start() { | |
this.intervalID = setInterval(this.#tick, 500) | |
} | |
#stop() { | |
clearInterval(this.intervalID) | |
} | |
#tick = () => { | |
const now = moment() | |
const expiresAt = moment(this.element.dateTime) | |
const duration = moment.duration(expiresAt.diff(now), "milliseconds") | |
this.expiredValue = expiresAt <= now | |
if (this.expiredValue) this.#stop() | |
this.element.innerHTML = duration.format("mm:ss", { forceLength: true, trim: false }) | |
} | |
}) | |
</script> | |
<%# if Rails.env.test? %> | |
<script type="module"> | |
import timemachine from "timemachine" | |
window.travelTo = (dateString) => timemachine.config({ dateString }) | |
travelTo("<%= Time.current.iso8601 %>") | |
</script> | |
<%# end %> | |
<style> | |
.ticking, .expired { display: none; } | |
body:has([data-timer-expired-value]) { | |
.loading { display: none; } | |
} | |
body:has([data-timer-expired-value="false"]) { | |
.ticking { display: inherit; } | |
.expired { display: none; } | |
} | |
body:has([data-timer-expired-value="true"]) { | |
.ticking { display: none; } | |
.expired { display: inherit; } | |
} | |
</style> | |
</head> | |
<body> | |
<h1> | |
<span class="loading">Loading</span> | |
<span class="ticking">Ticking</span> | |
<span class="expired">Expired</span> | |
</h1> | |
<time datetime="<%= @timer.iso8601 %>" data-controller="timer" data-timer-expired-value="<%= @timer.past? %>">Loading...</time> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment