This commit is contained in:
7
test/application_system_test_case.rb
Normal file
7
test/application_system_test_case.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
||||
include SystemTestHelper
|
||||
|
||||
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ]
|
||||
end
|
||||
19
test/channels/application_cable/connection_test.rb
Normal file
19
test/channels/application_cable/connection_test.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
require "test_helper"
|
||||
|
||||
module ApplicationCable
|
||||
class ConnectionTest < ActionCable::Connection::TestCase
|
||||
test "connects with cookies" do
|
||||
users(:kevin).sessions.start!(user_agent: "test", ip_address: "10.0.0.1").tap do |session|
|
||||
cookies.signed[:session_token] = session.token
|
||||
end
|
||||
|
||||
connect
|
||||
|
||||
assert_equal users(:kevin), connection.current_user
|
||||
end
|
||||
|
||||
test "rejects connection without cookies" do
|
||||
assert_reject_connection { connect }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
33
test/controllers/books/bookmarks_controller_test.rb
Normal file
33
test/controllers/books/bookmarks_controller_test.rb
Normal 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
|
||||
25
test/controllers/books/leaves/moves_controller_test.rb
Normal file
25
test/controllers/books/leaves/moves_controller_test.rb
Normal 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
|
||||
32
test/controllers/books/publications_controller_test.rb
Normal file
32
test/controllers/books/publications_controller_test.rb
Normal 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
|
||||
89
test/controllers/books_controller_test.rb
Normal file
89
test/controllers/books_controller_test.rb
Normal 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
|
||||
29
test/controllers/custom_styles_controller_test.rb
Normal file
29
test/controllers/custom_styles_controller_test.rb
Normal 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
|
||||
48
test/controllers/first_runs_controller_test.rb
Normal file
48
test/controllers/first_runs_controller_test.rb
Normal 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
|
||||
20
test/controllers/join_codes_controller_test.rb
Normal file
20
test/controllers/join_codes_controller_test.rb
Normal 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
|
||||
54
test/controllers/leafables_controller_test.rb
Normal file
54
test/controllers/leafables_controller_test.rb
Normal 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
|
||||
26
test/controllers/pages/edits_controller_test.rb
Normal file
26
test/controllers/pages/edits_controller_test.rb
Normal 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
|
||||
86
test/controllers/pages_controller_test.rb
Normal file
86
test/controllers/pages_controller_test.rb
Normal 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
|
||||
41
test/controllers/pictures_controller_test.rb
Normal file
41
test/controllers/pictures_controller_test.rb
Normal 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
|
||||
37
test/controllers/sections_controller_test.rb
Normal file
37
test/controllers/sections_controller_test.rb
Normal 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
|
||||
18
test/controllers/sessions/transfers-controller_test.rb
Normal file
18
test/controllers/sessions/transfers-controller_test.rb
Normal 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
|
||||
52
test/controllers/sessions_controller_test.rb
Normal file
52
test/controllers/sessions_controller_test.rb
Normal 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
|
||||
41
test/controllers/users/profiles_controller_test.rb
Normal file
41
test/controllers/users/profiles_controller_test.rb
Normal 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
|
||||
81
test/controllers/users_controller_test.rb
Normal file
81
test/controllers/users_controller_test.rb
Normal 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
|
||||
34
test/fixtures/accesses.yml
vendored
Normal file
34
test/fixtures/accesses.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
david_handbook:
|
||||
user: david
|
||||
book: handbook
|
||||
level: editor
|
||||
|
||||
david_manual:
|
||||
user: david
|
||||
book: manual
|
||||
level: editor
|
||||
|
||||
jason_handbook:
|
||||
user: jason
|
||||
book: handbook
|
||||
level: editor
|
||||
|
||||
jason_manual:
|
||||
user: jason
|
||||
book: manual
|
||||
level: editor
|
||||
|
||||
jz_handbook:
|
||||
user: jz
|
||||
book: handbook
|
||||
level: reader
|
||||
|
||||
jz_manual:
|
||||
user: jz
|
||||
book: manual
|
||||
level: reader
|
||||
|
||||
kevin_handbook:
|
||||
user: kevin
|
||||
book: handbook
|
||||
level: editor
|
||||
3
test/fixtures/accounts.yml
vendored
Normal file
3
test/fixtures/accounts.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
signal:
|
||||
name: 37signals
|
||||
join_code: cs3s-enl1-EKC3
|
||||
9
test/fixtures/action_text/markdowns.yml
vendored
Normal file
9
test/fixtures/action_text/markdowns.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
welcome:
|
||||
record: welcome (Page)
|
||||
name: body
|
||||
content: This is _such_ a great handbook.
|
||||
|
||||
summary:
|
||||
record: summary (Page)
|
||||
name: body
|
||||
content: Thanks for reading!
|
||||
4
test/fixtures/active_storage/attachments.yml
vendored
Normal file
4
test/fixtures/active_storage/attachments.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
handbook_reading_image:
|
||||
name: image
|
||||
record: reading (Picture)
|
||||
blob: handbook_reading_image_blob
|
||||
1
test/fixtures/active_storage/blobs.yml
vendored
Normal file
1
test/fixtures/active_storage/blobs.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
handbook_reading_image_blob: <%= ActiveStorage::FixtureSet.blob filename: "reading.webp", service_name: "test" %>
|
||||
7
test/fixtures/books.yml
vendored
Normal file
7
test/fixtures/books.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
handbook:
|
||||
title: Handbook
|
||||
slug: handbook
|
||||
|
||||
manual:
|
||||
title: Manual
|
||||
slug: manual
|
||||
0
test/fixtures/files/.keep
vendored
Normal file
0
test/fixtures/files/.keep
vendored
Normal file
BIN
test/fixtures/files/reading.webp
vendored
Normal file
BIN
test/fixtures/files/reading.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
BIN
test/fixtures/files/white-rabbit.webp
vendored
Normal file
BIN
test/fixtures/files/white-rabbit.webp
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
27
test/fixtures/leaves.yml
vendored
Normal file
27
test/fixtures/leaves.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
welcome_section:
|
||||
book: handbook
|
||||
title: The Welcome Section
|
||||
leafable: welcome (Section)
|
||||
position_score: 1
|
||||
status: active
|
||||
|
||||
welcome_page:
|
||||
book: handbook
|
||||
title: Welcome to The Handbook!
|
||||
leafable: welcome (Page)
|
||||
position_score: 2
|
||||
status: active
|
||||
|
||||
summary_page:
|
||||
book: handbook
|
||||
title: Summary
|
||||
leafable: summary (Page)
|
||||
position_score: 3
|
||||
status: active
|
||||
|
||||
reading_picture:
|
||||
book: handbook
|
||||
title: Reading
|
||||
leafable: reading (Picture)
|
||||
position_score: 4
|
||||
status: active
|
||||
4
test/fixtures/pages.yml
vendored
Normal file
4
test/fixtures/pages.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
welcome: {}
|
||||
|
||||
summary: {}
|
||||
|
||||
1
test/fixtures/pictures.yml
vendored
Normal file
1
test/fixtures/pictures.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
reading: {}
|
||||
1
test/fixtures/sections.yml
vendored
Normal file
1
test/fixtures/sections.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
welcome: {}
|
||||
25
test/fixtures/users.yml
vendored
Normal file
25
test/fixtures/users.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<% password_digest = BCrypt::Password.create("secret123456") %>
|
||||
|
||||
david:
|
||||
name: David
|
||||
email_address: david@37signals.com
|
||||
password_digest: <%= password_digest %>
|
||||
role: administrator
|
||||
|
||||
jason:
|
||||
name: Jason
|
||||
email_address: jason@37signals.com
|
||||
password_digest: <%= password_digest %>
|
||||
role: administrator
|
||||
|
||||
jz:
|
||||
name: JZ
|
||||
email_address: jz@37signals.com
|
||||
password_digest: <%= password_digest %>
|
||||
role: member
|
||||
|
||||
kevin:
|
||||
name: Kevin
|
||||
email_address: kevin@37signals.com
|
||||
password_digest: <%= password_digest %>
|
||||
role: member
|
||||
0
test/helpers/.keep
Normal file
0
test/helpers/.keep
Normal file
0
test/integration/.keep
Normal file
0
test/integration/.keep
Normal file
11
test/lib/markdown_renderer_test.rb
Normal file
11
test/lib/markdown_renderer_test.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
require "test_helper"
|
||||
|
||||
class MarkdownRendererTest < ActiveSupport::TestCase
|
||||
test "it generates unique IDs for headers" do
|
||||
markdown = MarkdownRenderer.build
|
||||
content = markdown.render("# Header 1\n\n## Duplicated Header\n\n### Duplicated header\n\n")
|
||||
|
||||
assert_includes content, "id='duplicated-header'"
|
||||
assert_includes content, "id='duplicated-header-2'"
|
||||
end
|
||||
end
|
||||
0
test/mailers/.keep
Normal file
0
test/mailers/.keep
Normal file
0
test/models/.keep
Normal file
0
test/models/.keep
Normal file
36
test/models/book/accessable_test.rb
Normal file
36
test/models/book/accessable_test.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
require "test_helper"
|
||||
|
||||
class Book::AccessableTest < ActiveSupport::TestCase
|
||||
test "update_access always grants read access to everyone when everyone_access is set" do
|
||||
book = Book.create!(title: "My new book")
|
||||
book.update_access(editors: [], readers: [])
|
||||
|
||||
assert book.everyone_access?
|
||||
|
||||
User.all.each do |user|
|
||||
assert book.accessable?(user: user)
|
||||
assert_not book.editable?(user: user) unless user.administrator?
|
||||
end
|
||||
end
|
||||
|
||||
test "update_access updates existing access" do
|
||||
book = Book.create!(title: "My new book", everyone_access: false)
|
||||
|
||||
book.update_access(editors: [ users(:kevin).id ], readers: [])
|
||||
assert book.editable?(user: users(:kevin))
|
||||
|
||||
book.update_access(editors: [], readers: [ users(:kevin).id ])
|
||||
assert book.accessable?(user: users(:kevin))
|
||||
assert_not book.editable?(user: users(:kevin))
|
||||
end
|
||||
|
||||
test "update_access removes stale accesses" do
|
||||
book = Book.create!(title: "My new book", everyone_access: false)
|
||||
|
||||
book.update_access(editors: [ users(:kevin).id ], readers: [ users(:jz).id ])
|
||||
assert_equal 2, book.accesses.size
|
||||
|
||||
book.update_access(editors: [ users(:kevin).id ], readers: [])
|
||||
assert_equal 1, book.accesses.size
|
||||
end
|
||||
end
|
||||
16
test/models/book_test.rb
Normal file
16
test/models/book_test.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
require "test_helper"
|
||||
|
||||
class BookTest < ActiveSupport::TestCase
|
||||
test "slug is generated from title" do
|
||||
book = Book.create!(title: "Hello, World!")
|
||||
assert_equal "hello-world", book.slug
|
||||
end
|
||||
|
||||
test "press a leafable" do
|
||||
leaf = books(:manual).press Page.new(body: "Important words"), title: "Introduction"
|
||||
|
||||
assert leaf.page?
|
||||
assert_equal "Important words", leaf.page.body.content.to_s
|
||||
assert_equal "Introduction", leaf.title
|
||||
end
|
||||
end
|
||||
37
test/models/first_run_test.rb
Normal file
37
test/models/first_run_test.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
require "test_helper"
|
||||
|
||||
class FirstRunTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
Book.destroy_all
|
||||
User.destroy_all
|
||||
Account.destroy_all
|
||||
end
|
||||
|
||||
test "creating makes first user an administrator" do
|
||||
user = create_first_run_user
|
||||
assert user.administrator?
|
||||
end
|
||||
|
||||
test "creates an account" do
|
||||
assert_changes -> { Account.count }, +1 do
|
||||
create_first_run_user
|
||||
end
|
||||
end
|
||||
|
||||
test "creates a demo book" do
|
||||
assert_changes -> { Book.count }, to: 1 do
|
||||
create_first_run_user
|
||||
end
|
||||
|
||||
book = Book.first
|
||||
|
||||
assert book.editable?(user: User.first)
|
||||
assert book.cover.attached?
|
||||
assert book.leaves.any?
|
||||
end
|
||||
|
||||
private
|
||||
def create_first_run_user
|
||||
FirstRun.create!({ name: "User", email_address: "user@example.com", password: "secret123456" })
|
||||
end
|
||||
end
|
||||
66
test/models/leaf/editable_test.rb
Normal file
66
test/models/leaf/editable_test.rb
Normal file
@@ -0,0 +1,66 @@
|
||||
require "test_helper"
|
||||
|
||||
class Leaf::EditableTest < ActiveSupport::TestCase
|
||||
test "editing a leafable records the edit" do
|
||||
leaves(:welcome_page).edit leafable_params: { body: "New body" }
|
||||
|
||||
assert_equal "New body", leaves(:welcome_page).page.body.content
|
||||
|
||||
assert leaves(:welcome_page).edits.last.revision?
|
||||
assert_equal "This is _such_ a great handbook.", leaves(:welcome_page).edits.last.page.body.content
|
||||
end
|
||||
|
||||
test "edits that are close together don't create new revisions" do
|
||||
assert_difference -> { leaves(:welcome_page).edits.count }, +1 do
|
||||
leaves(:welcome_page).edit leafable_params: { body: "First change" }
|
||||
end
|
||||
|
||||
freeze_time
|
||||
travel 1.minute
|
||||
|
||||
assert_no_difference -> { leaves(:welcome_page).edits.count } do
|
||||
leaves(:welcome_page).edit leafable_params: { body: "Second change" }
|
||||
end
|
||||
|
||||
assert_equal "Second change", leaves(:welcome_page).page.body.content
|
||||
assert_equal Time.now, leaves(:welcome_page).edits.last.updated_at
|
||||
|
||||
travel 1.hour
|
||||
|
||||
assert_difference -> { leaves(:welcome_page).edits.count }, +1 do
|
||||
leaves(:welcome_page).edit leafable_params: { body: "Third change" }
|
||||
end
|
||||
end
|
||||
|
||||
test "changing a leaf title doesn't create a revision" do
|
||||
assert_no_difference -> { Edit.count } do
|
||||
leaves(:welcome_page).edit leaf_params: { title: "New title" }
|
||||
end
|
||||
|
||||
assert_equal "New title", leaves(:welcome_page).title
|
||||
end
|
||||
|
||||
test "changes that don't affect the leafable don't create a revision" do
|
||||
assert_no_difference -> { Edit.count } do
|
||||
leaves(:welcome_page).edit leafable_params: {}
|
||||
end
|
||||
end
|
||||
|
||||
test "editing a leafable with an attachment includes the attachments in the new version" do
|
||||
assert leaves(:reading_picture).picture.image.attached?
|
||||
|
||||
leaves(:reading_picture).edit leaf_params: { title: "New title" }
|
||||
|
||||
assert_equal "New title", leaves(:reading_picture).title
|
||||
assert leaves(:reading_picture).picture.image.attached?
|
||||
end
|
||||
|
||||
test "trashing a leaf records the edit" do
|
||||
leaves(:welcome_page).trashed!
|
||||
|
||||
assert leaves(:welcome_page).trashed?
|
||||
|
||||
assert leaves(:welcome_page).edits.last.trash?
|
||||
assert_equal "This is _such_ a great handbook.", leaves(:welcome_page).edits.last.page.body.content
|
||||
end
|
||||
end
|
||||
96
test/models/leaf/positionable_test.rb
Normal file
96
test/models/leaf/positionable_test.rb
Normal file
@@ -0,0 +1,96 @@
|
||||
require "test_helper"
|
||||
|
||||
class Leaf::PositionableTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@leaves = books(:handbook).leaves.positioned
|
||||
end
|
||||
|
||||
test "items are sorted in positioned order" do
|
||||
assert_equal [ leaves(:welcome_section), leaves(:welcome_page), leaves(:summary_page), leaves(:reading_picture) ], @leaves
|
||||
end
|
||||
|
||||
test "items can be moved earlier" do
|
||||
leaves(:welcome_page).move_to_position(0)
|
||||
|
||||
assert_equal [ leaves(:welcome_page), leaves(:welcome_section), leaves(:summary_page), leaves(:reading_picture) ], @leaves.reload
|
||||
end
|
||||
|
||||
test "items can be moved beyond the start, which puts them at the start" do
|
||||
leaves(:welcome_page).move_to_position(-99)
|
||||
|
||||
assert_equal [ leaves(:welcome_page), leaves(:welcome_section), leaves(:summary_page), leaves(:reading_picture) ], @leaves.reload
|
||||
end
|
||||
|
||||
test "items can be moved later" do
|
||||
leaves(:welcome_section).move_to_position(2)
|
||||
|
||||
assert_equal [ leaves(:welcome_page), leaves(:summary_page), leaves(:welcome_section), leaves(:reading_picture) ], @leaves.reload
|
||||
end
|
||||
|
||||
test "items can be moved beyond the end, which puts them at the end" do
|
||||
leaves(:welcome_section).move_to_position(99)
|
||||
|
||||
assert_equal [ leaves(:welcome_page), leaves(:summary_page), leaves(:reading_picture), leaves(:welcome_section) ], @leaves.reload
|
||||
end
|
||||
|
||||
test "items can be moved to their existing position" do
|
||||
leaves(:welcome_page).move_to_position(1)
|
||||
|
||||
assert_equal [ leaves(:welcome_section), leaves(:welcome_page), leaves(:summary_page), leaves(:reading_picture) ], @leaves.reload
|
||||
end
|
||||
|
||||
test "items can be moved in blocks" do
|
||||
leaves(:welcome_section).move_to_position(1, followed_by: [ leaves(:welcome_page), leaves(:summary_page) ])
|
||||
|
||||
assert_equal [ leaves(:reading_picture), leaves(:welcome_section), leaves(:welcome_page), leaves(:summary_page) ], @leaves.reload
|
||||
end
|
||||
|
||||
test "new items are inserted at the end" do
|
||||
new_page = books(:handbook).press Page.new(body: "New Page"), title: "New Page"
|
||||
|
||||
assert_equal new_page, books(:handbook).leaves.positioned.last
|
||||
end
|
||||
|
||||
test "the first item in the collection has the expected score" do
|
||||
books(:handbook).leaves.destroy_all
|
||||
new_page = books(:handbook).press Page.new(body: "New Page"), title: "New Page"
|
||||
|
||||
assert_equal 1, new_page.position_score
|
||||
end
|
||||
|
||||
test "positioning is rebalanced when necessary" do
|
||||
leaves(:welcome_section).update!(position_score: 1e-11)
|
||||
leaves(:welcome_page).update!(position_score: 2e-11)
|
||||
|
||||
leaves(:summary_page).move_to_position(1)
|
||||
|
||||
assert_equal leaves(:summary_page), @leaves.reload.second
|
||||
assert_equal [ 1, 2, 3, 4 ], @leaves.pluck(:position_score)
|
||||
end
|
||||
|
||||
test "items know their neighbours" do
|
||||
assert_equal leaves(:welcome_section), leaves(:welcome_page).previous
|
||||
assert_equal leaves(:summary_page), leaves(:welcome_page).next
|
||||
|
||||
assert_nil leaves(:welcome_section).previous
|
||||
assert_nil leaves(:reading_picture).next
|
||||
end
|
||||
|
||||
test "only active items are included as neighbours" do
|
||||
assert_equal leaves(:summary_page), leaves(:welcome_page).next
|
||||
|
||||
leaves(:summary_page).trashed!
|
||||
|
||||
assert_equal leaves(:reading_picture), leaves(:welcome_page).next
|
||||
end
|
||||
|
||||
test "only active items are counted when determining position" do
|
||||
leaves(:welcome_page).trashed!
|
||||
|
||||
leaves(:welcome_section).move_to_position(1)
|
||||
assert_equal [ leaves(:summary_page), leaves(:welcome_section), leaves(:reading_picture) ], @leaves.reload.active
|
||||
|
||||
leaves(:welcome_section).move_to_position(0)
|
||||
assert_equal [ leaves(:welcome_section), leaves(:summary_page), leaves(:reading_picture) ], @leaves.reload.active
|
||||
end
|
||||
end
|
||||
13
test/models/leaf_test.rb
Normal file
13
test/models/leaf_test.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
require "test_helper"
|
||||
|
||||
class LeafTest < ActiveSupport::TestCase
|
||||
test "slug is generated from title" do
|
||||
leaf = Leaf.new(title: "Hello, World!")
|
||||
assert_equal "hello-world", leaf.slug
|
||||
end
|
||||
|
||||
test "slug is never completely blank" do
|
||||
leaf = Leaf.new(title: "")
|
||||
assert_equal "-", leaf.slug
|
||||
end
|
||||
end
|
||||
10
test/models/page_test.rb
Normal file
10
test/models/page_test.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
require "test_helper"
|
||||
|
||||
class PageTest < ActiveSupport::TestCase
|
||||
test "html preview" do
|
||||
page = Page.new(body: "# Hello\n\nWorld!")
|
||||
|
||||
assert_match /<h1>Hello<\/h1>/, page.html_preview
|
||||
assert_match /<p>World!<\/p>/, page.html_preview
|
||||
end
|
||||
end
|
||||
11
test/models/qr_code_link_test.rb
Normal file
11
test/models/qr_code_link_test.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
require "test_helper"
|
||||
|
||||
class QrCodeLinkTest < ActiveSupport::TestCase
|
||||
test "links can be signed and verified" do
|
||||
link = QrCodeLink.new "https://example.com"
|
||||
signed_link = link.signed
|
||||
|
||||
verified = QrCodeLink.from_signed(signed_link)
|
||||
assert_equal link.url, verified.url
|
||||
end
|
||||
end
|
||||
14
test/models/user/role_test.rb
Normal file
14
test/models/user/role_test.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
require "test_helper"
|
||||
|
||||
class User::RoleTest < ActiveSupport::TestCase
|
||||
test "creating users makes them members by default" do
|
||||
assert User.create!(name: "User", email_address: "user@example.com", password: "secret123456").member?
|
||||
end
|
||||
|
||||
test "can_administer?" do
|
||||
assert User.new(role: :administrator).can_administer?
|
||||
|
||||
assert_not User.new(role: :member).can_administer?
|
||||
assert_not User.new.can_administer?
|
||||
end
|
||||
end
|
||||
20
test/models/user_test.rb
Normal file
20
test/models/user_test.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
require "test_helper"
|
||||
|
||||
class UserTest < ActiveSupport::TestCase
|
||||
test "user does not prevent very long passwords" do
|
||||
users(:david).update(password: "secret" * 50)
|
||||
assert users(:david).valid?
|
||||
end
|
||||
|
||||
test "new users get access to everyone books" do
|
||||
everyone_book = Book.create!(title: "My new book", everyone_access: true)
|
||||
other_book = Book.create!(title: "My secret book", everyone_access: false)
|
||||
|
||||
bob = User.create!(email_address: "bob@example.com", name: "Bob", password: "secret123456")
|
||||
|
||||
assert everyone_book.accessable?(user: bob)
|
||||
assert_not everyone_book.editable?(user: bob)
|
||||
|
||||
assert_not other_book.accessable?(user: bob)
|
||||
end
|
||||
end
|
||||
19
test/system/edit_page_test.rb
Normal file
19
test/system/edit_page_test.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
require "application_system_test_case"
|
||||
|
||||
class EditPageTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
sign_in "kevin@37signals.com"
|
||||
end
|
||||
|
||||
test "edit page" do
|
||||
visit edit_book_page_url(books(:handbook), leaves(:welcome_page))
|
||||
assert_selector "house-md"
|
||||
|
||||
fill_house_editor "page[body]", with: "Welcome to the handbook! This is the **first** page."
|
||||
|
||||
click_button "Save"
|
||||
|
||||
assert_selector ".house-md-content", text: "Welcome to the handbook! This is the **first** page."
|
||||
assert_selector ".house-md-content strong", text: "first"
|
||||
end
|
||||
end
|
||||
38
test/system/publish_book_test.rb
Normal file
38
test/system/publish_book_test.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
require "application_system_test_case"
|
||||
|
||||
class PublishTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
sign_in "kevin@37signals.com"
|
||||
end
|
||||
|
||||
test "create and publish a book" do
|
||||
visit new_book_url
|
||||
|
||||
fill_in "Book title", with: "My Book of Jokes"
|
||||
fill_in "Author", with: "Kevin"
|
||||
within "footer" do
|
||||
click_button
|
||||
end
|
||||
|
||||
assert_text "My Book of Jokes"
|
||||
|
||||
click_on "Add a new section page"
|
||||
fill_in "leaf_title", with: "A horse walks into a bar"
|
||||
click_on "Save"
|
||||
|
||||
click_on "Add a new section page"
|
||||
fill_in "leaf_title", with: "And the barman says 'Why the long face?'"
|
||||
click_on "Save"
|
||||
|
||||
find(class: "switch__btn").click
|
||||
public_url = find(id: "invite_url").value
|
||||
|
||||
using_session "public" do
|
||||
visit public_url
|
||||
assert_text "My Book of Jokes"
|
||||
|
||||
page.send_keys :arrow_right
|
||||
assert_text "A horse walks into a bar"
|
||||
end
|
||||
end
|
||||
end
|
||||
15
test/test_helper.rb
Normal file
15
test/test_helper.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
ENV["RAILS_ENV"] ||= "test"
|
||||
require_relative "../config/environment"
|
||||
require "rails/test_help"
|
||||
|
||||
module ActiveSupport
|
||||
class TestCase
|
||||
# Run tests in parallel with specified workers
|
||||
parallelize(workers: :number_of_processors)
|
||||
|
||||
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
|
||||
fixtures :all
|
||||
|
||||
include SessionTestHelper
|
||||
end
|
||||
end
|
||||
16
test/test_helpers/session_test_helper.rb
Normal file
16
test/test_helpers/session_test_helper.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module SessionTestHelper
|
||||
def parsed_cookies
|
||||
ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash)
|
||||
end
|
||||
|
||||
def sign_in(user)
|
||||
user = users(user) unless user.is_a? User
|
||||
post session_url, params: { email_address: user.email_address, password: "secret123456" }
|
||||
assert cookies[:session_token].present?
|
||||
end
|
||||
|
||||
def sign_out
|
||||
delete session_url
|
||||
assert_not cookies[:session_token].present?
|
||||
end
|
||||
end
|
||||
20
test/test_helpers/system_test_helper.rb
Normal file
20
test/test_helpers/system_test_helper.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
module SystemTestHelper
|
||||
include ActionView::Helpers::JavaScriptHelper
|
||||
|
||||
def sign_in(email_address, password = "secret123456")
|
||||
visit new_session_url
|
||||
|
||||
fill_in "email_address", with: email_address
|
||||
fill_in "password", with: password
|
||||
|
||||
click_on "log_in"
|
||||
assert_selector "h2", text: "Handbook"
|
||||
end
|
||||
|
||||
def fill_house_editor(name, content)
|
||||
execute_script <<~JS
|
||||
const editor = document.querySelector("[name='#{name}']")
|
||||
editor.value = "#{escape_javascript(content)}"
|
||||
JS
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user