This commit is contained in:
2025-11-07 13:34:32 -08:00
commit 1e8c5a972b
436 changed files with 11000 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
require "test_helper"
class ActionText::Markdown::UploadsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "attach a file" do
assert_changes -> { ActiveStorage::Attachment.count }, 1 do
post action_text_markdown_uploads_url, params: {
record_gid: pages(:welcome).to_signed_global_id.to_s,
attribute_name: "body",
file: fixture_file_upload("reading.webp", "image/webp")
}, as: :xhr
end
assert_response :success
end
test "view attached file" do
markdown = pages(:welcome).body.tap(&:save!)
markdown.uploads.attach fixture_file_upload("reading.webp", "image/webp")
attachment = pages(:welcome).body.uploads.last
get action_text_markdown_upload_url(slug: attachment.slug)
assert_response :redirect
assert_match /\/rails\/active_storage\/.*\/reading\.webp/, @response.redirect_url
end
end

View File

@@ -0,0 +1,33 @@
require "test_helper"
class Books::BookmarksControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "show includes a link to read the last read leaf" do
cookies["reading_progress_#{books(:handbook).id}"] = "#{leaves(:welcome_page).id}/3"
get book_bookmark_url(books(:handbook))
assert_response :success
assert_select "a", /Resume reading/
end
test "show includes a link to start reading if the last read leaf has been trashed" do
leaves(:welcome_page).trashed!
cookies["reading_progress_#{books(:handbook).id}"] = "#{leaves(:welcome_page).id}/3"
get book_bookmark_url(books(:handbook))
assert_response :success
assert_select "a", /Start reading/
end
test "show includes a link to start reading if no reading progress has been recorded" do
get book_bookmark_url(books(:handbook))
assert_response :success
assert_select "a", /Start reading/
end
end

View File

@@ -0,0 +1,25 @@
require "test_helper"
class Books::Leaves::MovesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "moving a single item" do
assert_equal [ leaves(:welcome_section), leaves(:welcome_page), leaves(:summary_page), leaves(:reading_picture) ], books(:handbook).leaves.positioned
post book_leaves_moves_url(books(:handbook), id: leaves(:welcome_page).id, position: 0)
assert_response :no_content
assert_equal [ leaves(:welcome_page), leaves(:welcome_section), leaves(:summary_page), leaves(:reading_picture) ], books(:handbook).leaves.positioned
end
test "moving multiple items" do
assert_equal [ leaves(:welcome_section), leaves(:welcome_page), leaves(:summary_page), leaves(:reading_picture) ], books(:handbook).leaves.positioned
post book_leaves_moves_url(books(:handbook), id: leaves(:summary_page, :reading_picture).map(&:id), position: 1)
assert_response :no_content
assert_equal [ leaves(:welcome_section), leaves(:summary_page), leaves(:reading_picture), leaves(:welcome_page) ], books(:handbook).leaves.positioned
end
end

View File

@@ -0,0 +1,32 @@
require "test_helper"
class Books::PublicationsTest < ActionDispatch::IntegrationTest
setup do
@book = books(:manual)
sign_in :david
end
test "publish a book" do
assert_changes -> { @book.reload.published? }, from: false, to: true do
patch book_publication_url(@book), params: { book: { published: "1" } }
end
@book.reload
assert_redirected_to book_slug_url(@book)
assert_equal "manual", @book.slug
end
test "edit book slug" do
@book.update! published: true
get edit_book_publication_url(@book)
assert_response :success
patch book_publication_url(@book), params: { book: { slug: "new-slug" } }
@book.reload
assert_redirected_to book_slug_url(@book)
assert_equal "new-slug", @book.slug
end
end

View File

@@ -0,0 +1,89 @@
require "test_helper"
class BooksControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "index lists the current user's books" do
get root_url
assert_response :success
assert_select "h2", text: "Handbook"
assert_select "h2", text: "Manual", count: 0
end
test "index includes published books, even when the user does not have access" do
books(:manual).update!(published: true)
get root_url
assert_response :success
assert_select "h2", text: "Handbook"
assert_select "h2", text: "Manual"
end
test "index shows published books when not logged in" do
books(:manual).update!(published: true)
sign_out
get root_url
assert_response :success
assert_select "h2", text: "Handbook", count: 0
assert_select "h2", text: "Manual"
end
test "index redirects to login if not signed in and no published books exist" do
sign_out
get root_url
assert_redirected_to new_session_url
end
test "create makes the current user an editor" do
assert_difference -> { Book.count }, +1 do
post books_url, params: { book: { title: "New Book", everyone_access: false } }
end
assert_redirected_to book_slug_url(Book.last)
book = Book.last
assert_equal "New Book", book.title
assert_equal 1, Book.last.accesses.count
assert book.editable?(user: users(:kevin))
end
test "create sets additional accesses" do
sign_in :jason
assert_difference -> { Book.count }, +1 do
post books_url, params: { book: { title: "New Book", everyone_access: false }, "editor_ids[]": users(:jz).id, "reader_ids[]": users(:kevin).id }
end
book = Book.last
assert_equal "New Book", book.title
assert_equal 3, Book.last.accesses.count
assert book.editable?(user: users(:jz))
assert book.accessable?(user: users(:kevin))
assert_not book.editable?(user: users(:kevin))
end
test "show only shows books the current user can access" do
get book_slug_url(books(:manual))
assert_response :not_found
get book_slug_url(books(:handbook))
assert_response :success
end
test "show includes OG metadata for public access" do
get book_slug_url(books(:handbook))
assert_response :success
assert_select "meta[property='og:title'][content='Handbook']"
assert_select "meta[property='og:url'][content='#{book_slug_url(books(:handbook))}']"
end
end

View File

@@ -0,0 +1,29 @@
require "test_helper"
class Accounts::CustomStylesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :david
end
test "edit" do
get edit_account_custom_styles_url
assert_response :ok
end
test "update" do
assert users(:david).administrator?
put account_custom_styles_url, params: { account: { custom_styles: ":root { --color-text: red; }" } }
assert_redirected_to edit_account_custom_styles_url
assert_equal accounts(:signal).custom_styles, ":root { --color-text: red; }"
end
test "non-admins cannot update" do
sign_in :kevin
assert users(:kevin).member?
put account_custom_styles_url, params: { account: { custom_styles: ":root { --color-text: red; }" } }
assert_response :forbidden
end
end

View File

@@ -0,0 +1,48 @@
require "test_helper"
class FirstRunsControllerTest < ActionDispatch::IntegrationTest
setup do
Book.destroy_all
User.destroy_all
end
test "new" do
get first_run_url
assert_response :success
end
test "new is not permitted when users exist" do
create_user
get first_run_url
assert_redirected_to root_url
end
test "create" do
assert_difference -> { User.count }, 1 do
post first_run_url, params: { user: { name: "New Person", email_address: "new@37signals.com", password: "secret123456" } }
end
assert_redirected_to root_url
assert parsed_cookies.signed[:session_token]
end
test "create is not permitted when users exist" do
create_user
assert_no_difference -> { User.count } do
post first_run_url, params: { user: { name: "New Person", email_address: "new@37signals.com", password: "secret123456" } }
end
assert_redirected_to root_url
end
private
def create_user
User.create! \
name: "Existing Person",
email_address: "user@example.com",
password: "secret123456"
end
end

View File

@@ -0,0 +1,20 @@
require "test_helper"
class Accounts::JoinCodesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :david
end
test "create new join code" do
assert_changes -> { accounts(:signal).reload.join_code } do
post account_join_code_url
assert_redirected_to users_url
end
end
test "only administrators can create new join codes" do
sign_in :jz
post account_join_code_url
assert_response :forbidden
end
end

View File

@@ -0,0 +1,54 @@
require "test_helper"
class LeafablesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "show" do
get leafable_slug_path(leaves(:welcome_page))
assert_response :success
assert_select "p", "This is such a great handbook."
end
test "show with public access to a published book" do
sign_out
books(:handbook).update!(published: true)
get leafable_slug_path(leaves(:welcome_page))
assert_response :success
assert_select "p", "This is such a great handbook."
end
test "show does not allow public access to an unpublished book" do
sign_out
get leafable_slug_path(leaves(:welcome_page))
assert_response :not_found
end
test "create" do
assert_changes -> { books(:handbook).leaves.count }, +1 do
post book_pages_path(books(:handbook), format: :turbo_stream), params: {
leaf: { title: "Another page" }, page: { body: "With interesting words." }
}
end
assert_response :success
end
test "create requires editor access" do
books(:handbook).access_for(user: users(:kevin)).update! level: :reader
assert_no_changes -> { books(:handbook).leaves.count } do
post book_pages_path(books(:handbook), format: :turbo_stream), params: {
leaf: { title: "Another page" }, page: { body: "With interesting words." }
}
end
assert_response :forbidden
end
end

View File

@@ -0,0 +1,26 @@
require "test_helper"
class Pages::EditsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "show an edit" do
leaves(:welcome_page).edit leafable_params: { body: "Completely new content" }
get page_edit_url(leaves(:welcome_page), leaves(:welcome_page).edits.last)
assert_response :success
assert_select "p", /such a great handbook/
assert_select "p", /Completely new content/
end
test "show latest edit" do
leaves(:welcome_page).edit leafable_params: { body: "Updated" }
get page_edit_url(leaves(:welcome_page), "latest")
assert_response :success
assert_select "p", /such a great handbook/
end
end

View File

@@ -0,0 +1,86 @@
require "test_helper"
class PagesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "show" do
get leafable_path(sample_page_leaf("## Hello"))
assert_response :ok
assert_select "h2", text: /Hello/
end
test "show sanitizes dangerous content" do
get leafable_path(sample_page_leaf(%(<div id="test"><script>alert("ouch")</script></div>)))
assert_select "#test", html: %(alert("ouch"))
end
test "show with HTML content in the markdown" do
get leafable_path(sample_page_leaf(%(<div id="test"><div style="text-align:center;">Hello</div></div>)))
assert_select "#test", html: %(<div style="text-align:center;">Hello</div>)
end
test "show with iframes" do
get leafable_path(sample_page_leaf(%(<div id="test"><iframe src="http://example.com"></iframe></div>)))
assert_select "#test", html: %(<iframe src="http://example.com"></iframe>)
end
test "show with tables in the markdown" do
get leafable_path(sample_page_leaf(%(| name | food |\n| ---- | ---- |\n| Kevin | Pizza |)))
assert_select "table th", text: "name"
assert_select "table th", text: "food"
assert_select "table td", text: "Kevin"
assert_select "table td", text: "Pizza"
end
test "create" do
post book_pages_path(books(:handbook), format: :turbo_stream), params: { leaf: { title: "Another page" }, page: { body: "With interesting words." } }
assert_response :success
new_page = Page.last
assert_equal "Another page", new_page.title
assert_equal "With interesting words.", new_page.body.content
assert_equal books(:handbook), new_page.leaf.book
end
test "create with default params" do
assert_changes -> { Page.count }, +1 do
post book_pages_path(books(:handbook), format: :turbo_stream)
end
assert_response :success
assert_equal "Untitled", Page.last.title
end
test "create at a specific position" do
assert_changes -> { Page.count }, +1 do
post book_pages_path(books(:handbook), format: :turbo_stream), params: { position: 2 }
end
assert_response :success
assert_equal 2, books(:handbook).leaves.before(Page.last.leaf).count
end
test "update" do
get edit_leafable_path(leaves(:welcome_page))
assert_response :ok
put leafable_path(leaves(:welcome_page)), params: { leaf: { title: "Better welcome" }, page: { body: "With even more interesting words." } }
assert_response :no_content
updated_page = Page.last
assert_equal "Better welcome", updated_page.title
assert_equal "With even more interesting words.", updated_page.body.content
end
private
def sample_page_leaf(markdown)
books(:handbook).press Page.new(body: markdown), title: "Sample"
end
end

View File

@@ -0,0 +1,41 @@
require "test_helper"
class PicturesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "update picture" do
get edit_leafable_path(leaves(:reading_picture))
assert_response :ok
put leafable_path(leaves(:reading_picture)), params: {
leaf: { title: "New picture" },
picture: {
image: fixture_file_upload("white-rabbit.webp", "image/webp")
} }
assert_response :no_content
updated_picture = Picture.last
assert_equal "New picture", updated_picture.title
assert_equal "white-rabbit.webp", updated_picture.image.filename.to_s
end
test "update caption" do
get edit_leafable_path(leaves(:reading_picture))
assert_response :ok
put leafable_path(leaves(:reading_picture)), params: {
picture: {
caption: "New caption"
} }
assert_response :no_content
updated_picture = Picture.last
assert_equal "New caption", updated_picture.caption
assert_equal "reading.webp", updated_picture.image.filename.to_s
end
end

View File

@@ -0,0 +1,37 @@
require "test_helper"
class SectionsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in :kevin
end
test "create" do
post book_sections_path(books(:handbook), format: :turbo_stream)
assert_response :success
new_section = Section.last
assert_equal "Section", new_section.title
assert_equal books(:handbook), new_section.leaf.book
end
test "update" do
put leafable_path(leaves(:welcome_section)), params: {
leaf: { title: "Title" },
section: { body: "Section body" }
}
assert_response :success
section = leaves(:welcome_section).reload.leafable
assert_equal "Title", section.title
assert_equal "Section body", section.body
end
test "update with no body supplied" do
put leafable_path(leaves(:welcome_section)), params: { leaf: { title: "New title" } }
assert_response :success
section = leaves(:welcome_section).reload.leafable
assert_equal "New title", section.title
assert_equal "New title", section.body
end
end

View File

@@ -0,0 +1,18 @@
require "test_helper"
class Sessions::TransfersControllerTest < ActionDispatch::IntegrationTest
test "show renders when not signed in" do
get session_transfer_url("some-token")
assert_response :success
end
test "update establishes a session when the code is valid" do
user = users(:david)
put session_transfer_url(user.transfer_id)
assert_redirected_to root_url
assert parsed_cookies.signed[:session_token]
end
end

View File

@@ -0,0 +1,52 @@
require "test_helper"
class SessionsControllerTest < ActionDispatch::IntegrationTest
ALLOWED_BROWSER = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15"
DISALLOWED_BROWSER = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0"
test "new" do
get new_session_url
assert_response :success
end
test "new redirects to first run when no users exist" do
User.destroy_all
get new_session_url
assert_redirected_to first_run_url
end
test "new denied with incompatible browser" do
get new_session_url, env: { "HTTP_USER_AGENT" => DISALLOWED_BROWSER }
assert_select "svg", message: /Your browser is not supported/
end
test "new allowed with compatible browser" do
get new_session_url, env: { "HTTP_USER_AGENT" => ALLOWED_BROWSER }
assert_select "svg", message: /Your browser is not supported/, count: 0
end
test "create with valid credentials" do
post session_url, params: { email_address: "david@37signals.com", password: "secret123456" }
assert_redirected_to root_url
assert parsed_cookies.signed[:session_token]
end
test "create with invalid credentials" do
post session_url, params: { email_address: "david@37signals.com", password: "wrong" }
assert_response :unauthorized
assert_nil parsed_cookies.signed[:session_token]
end
test "destroy" do
sign_in :david
delete session_url
assert_redirected_to root_url
assert_not cookies[:session_token].present?
end
end

View File

@@ -0,0 +1,41 @@
require "test_helper"
class Users::ProfilesControllerTest < ActionDispatch::IntegrationTest
test "show" do
sign_in :david
get user_profile_url(users(:david))
assert_response :success
get user_profile_url(users(:kevin))
assert_response :success
end
test "edit is accessable to the current user" do
sign_in :david
get edit_user_profile_url(users(:david))
assert_response :success
get edit_user_profile_url(users(:kevin))
assert_response :forbidden
end
test "update modifies profile for current user" do
sign_in :kevin
put user_profile_url(users(:kevin)), params: { user: { name: "Bob" } }
assert_redirected_to users_url
assert_equal "Bob", users(:kevin).reload.name
end
test "update prohibits modifying profile of other users" do
sign_in :david
put user_profile_url(users(:kevin)), params: { user: { name: "Bob" } }
assert_response :forbidden
assert_equal "Kevin", users(:kevin).reload.name
end
end

View File

@@ -0,0 +1,81 @@
require "test_helper"
class UsersControllerTest < ActionDispatch::IntegrationTest
setup do
@join_code = accounts(:signal).join_code
end
test "new" do
get join_url(@join_code)
assert_response :success
end
test "new does not allow a signed in user" do
sign_in :david
get join_url(@join_code)
assert_redirected_to root_url
end
test "new requires a join code" do
get join_url("not")
assert_response :not_found
end
test "create" do
assert_difference -> { User.count }, 1 do
post join_url(@join_code), params: { user: { name: "New Person", email_address: "new@37signals.com", password: "secret123456" } }
end
assert_redirected_to root_url
user = User.last
assert_equal user.id, Session.find_by(token: parsed_cookies.signed[:session_token]).user.id
end
test "creating a new user with an existing email address redirects to login screen" do
assert_no_difference -> { User.count } do
post join_url(@join_code), params: { user: { name: "Another David", email_address: users(:david).email_address, password: "secret123456" } }
end
assert_redirected_to new_session_url(email_address: users(:david).email_address)
end
test "update" do
sign_in :david
assert users(:david).administrator?
put user_url(users(:kevin)), params: { user: { role: "administrator" } }
assert_redirected_to users_url
assert users(:kevin).reload.administrator?
end
test "update does not allow non-admins to change roles" do
sign_in :kevin
assert_not users(:kevin).administrator?
put user_url(users(:kevin)), params: { user: { role: "administrator" } }
assert_response :forbidden
assert_not users(:kevin).reload.administrator?
end
test "destroy" do
sign_in :david
assert_difference -> { User.active.count }, -1 do
delete user_url(users(:kevin))
end
assert_redirected_to users_url
assert_nil User.active.find_by(id: users(:kevin).id)
end
test "destroy is not allowed to non-admins" do
sign_in :kevin
delete user_url(users(:david))
assert_response :forbidden
end
end