Skip to content

Instantly share code, notes, and snippets.

@seanpdoyle
Last active February 15, 2024 23:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanpdoyle/61ff045986e3ad2f0beee19cc2d0fa23 to your computer and use it in GitHub Desktop.
Save seanpdoyle/61ff045986e3ad2f0beee19cc2d0fa23 to your computer and use it in GitHub Desktop.
Add a `binding.irb` to the test, then execute `ruby application.rb`
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