Files
numolus/test/models/magic_link_test.rb
T
wkhandClaude Opus 5.5 e14bada114 Add Rails backend: accounts via magic link, server documents, sharing
The app becomes a Rails 8 application; the Vue frontend moves to
app/frontend and is served through vite_rails.

- Without an account documents stay in the browser (IndexedDB). Sign-in
  is by magic link or the 6-digit code from the same mail; afterwards
  local documents can be uploaded into the account.
- Server documents (/d/<id>) with versioned saves and a single-editor
  lock per browser tab; others see them read-only and follow by polling.
- Sharing via link (works without an account) and via e-mail invitation,
  roles viewer/editor; the owner manages links and people.
- Store gains a read-only mode that blocks all content changes.
- Solid Queue, Cache and Cable share the one PostgreSQL database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 20:09:06 +02:00

50 lines
1.9 KiB
Ruby

require "test_helper"
class MagicLinkTest < ActiveSupport::TestCase
test "stores only digests and redeems once, creating the user" do
link = MagicLink.issue!(email: " New@Example.com ")
assert_equal "new@example.com", link.email
assert_not_equal link.token, link.token_digest
assert_equal link, MagicLink.find_by_token(link.token)
user = link.redeem!
assert_equal "new@example.com", user.email
assert_nil MagicLink.find_by_token(link.token), "used"
end
test "expires" do
link = MagicLink.issue!(email: "a@example.com")
travel MagicLink::LOGIN_TTL + 1.second do
assert_nil MagicLink.find_by_token(link.token)
end
end
test "code: wrong attempts burn the link" do
link = MagicLink.issue!(email: "a@example.com")
wrong = link.code == "000000" ? "111111" : "000000"
MagicLink::MAX_CODE_ATTEMPTS.times { assert_nil MagicLink.find_by_code("a@example.com", wrong) }
assert_nil MagicLink.find_by_code("a@example.com", link.code)
end
test "code accepts formatting and the right email only" do
link = MagicLink.issue!(email: "a@example.com")
assert_equal link, MagicLink.find_by_code("A@example.com", link.code.chars.each_slice(3).map(&:join).join(" "))
assert_nil MagicLink.find_by_code("b@example.com", link.code)
end
test "return_to only allows local paths" do
assert_equal "/d/abc", MagicLink.safe_path("/d/abc")
assert_nil MagicLink.safe_path("https://evil.example")
assert_nil MagicLink.safe_path("//evil.example")
end
test "invitation grants the document on redeem" do
owner = create_user("owner@example.com")
doc = create_document(owner)
link = MagicLink.issue!(email: "guest@example.com", purpose: :invitation, document: doc, role: :editor, invited_by: owner)
user = link.redeem!
assert_equal :editor, doc.role_for(user:)
assert_equal "/d/#{doc.id}", link.destination
end
end