25 | <%= radio_button_tag(:strategy, "recent") %>
26 | <%= label_tag :strategy_recent do %>
27 | Get most recent <%= select_tag(:recent_number, options_for_select([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])) %> chapter(s)
28 | <% end %>
29 |
30 |
31 | <% end %>
32 |
33 |
34 | <% if @doc_id %>
35 | <%= link_to "Download file", "/documents/#{@doc_id}", method: :post %>
36 | <% end %>
37 | <% flash.each do |name, msg| -%>
38 | <%= content_tag :div, msg, class: name %>
39 | <% end -%>
40 |
41 |
Loading...
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
Enter a link to the story in the box above, select the file type you want for the ebook, and hit Get. See the About page for a list of supported sites.
25 | <%= yield %>
26 | <%= render 'shared/footer' %>
27 |
28 |
29 | <%= stylesheet_link_tag 'application', media: 'all'%>
30 | <%= javascript_include_tag 'application'%>
31 | <%= render partial: "shared/google_analytics"%>
32 |
33 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/views/layouts/mailer.text.erb:
--------------------------------------------------------------------------------
1 | <%= yield %>
2 |
--------------------------------------------------------------------------------
/app/views/release-notes/1.md:
--------------------------------------------------------------------------------
1 | **November 28th, 2019 - Omnibuser is no longer being actively maintained**
2 |
3 | I will continue to fix critical bugs, but I will not be doing any new feature development or addressing minor problems.
4 |
5 | I originally built Omnibuser as a way to learn Ruby on Rails. It was mostly for personal use, and I didn't expect many people to be interested in it. I ended up being wrong about that - a slow trickle of people started using it after I posted it on reddit and since then the numbers have steadily grown. I've been amazed and thankful for how many people found my little fanfic app useful - we've had over 300,000 downloads since release!
6 |
7 | I had a lot more ideas for Omnibuser, new features and ways to improve the user experience. I use it quite a bit myself, and I know how clunky and annoying it can be, and how many cool things it can't do. But shortly after releasing V1.1, I got an awesome job thanks to my new Rails skills. As a very junior developer, writing code for 8 hours a day was pretty draining, and I found I wasn't really able to work on personal projects on top of that. So all the ideas I've had, and all the cool ideas people have emailed me about, have been gathering dust on a Trello board somewhere for the past couple of years.
8 |
9 | I'm a bit more experienced now, and I'm finally able to put consistent time into personal projects on top of my day job. I thought about coming back to Omnibuser and adding all those cool features. But it's been a long time since I've worked on it, and looking at it now is like reading someone else's code. The code quality is pretty terrible - it looks like it was written by someone just starting to learn Rails! I wouldn't be happy slapping new stuff on top of such an amateurish foundation, I'd have to rewrite the whole thing.
10 |
11 | So instead of doing that, I'm working on a new app, which takes a different approach to the "reading fanfic as an ebook" idea. It's still in early stages, but I'm very excited about it, and when it's released I think it will make Omnibuser obsolete. So if you've been waiting patiently to see if your suggestion ever makes it into Omnibuser, all hope is not lost. I'll be taking on board all the feedback I've received, and I'll aim to make the new app the best fanfic reading tool possible!
12 |
13 | No release date for the new app yet, it won't be ready for at least a few months. If you'd be interested in helping me beta test closer to release, please do get in touch!
14 |
--------------------------------------------------------------------------------
/app/views/shared/_footer.html.erb:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/views/shared/_google_analytics.html.erb:
--------------------------------------------------------------------------------
1 | <% if Rails.env == "production" %>
2 |
12 | <% end %>
13 |
--------------------------------------------------------------------------------
/app/views/shared/_header.html.erb:
--------------------------------------------------------------------------------
1 |
4 | Omnibuser is a simple tool for converting online fiction into ebooks. I made this in my spare time because I was sick of my Kindle gathering dust while I read web serials.
5 |
6 |
7 | Just enter a link to the story you want, and Omnibuser will grab it and deliver it to you in whatever format you want.
8 |
9 |
10 |
11 |
Supported sites
12 |
13 | Right now I'm just supporting the sites that I personally use, that don't already have an ebook download feature (AO3 already has one, for example). If there are any sites I've missed that you'd like to see, get in contact with me and I'll look into it.
14 |
15 |
16 |
fanfiction.net
17 |
fictionpress.com
18 |
forums.spacebattles.com
19 |
forums.sufficientvelocity.com
20 |
forums.questionablequesting.com
21 |
22 |
Currently the forums are only supported if the story thread uses threadmarks.
23 |
24 |
25 |
26 |
Why is it taking so long to fetch the story?
27 |
28 | In order to be considerate to the hosting sites, Omnibuser will only fetch a new chapter from a particular site once every couple of seconds. This means that if several users are trying to get stories from the same site at the same time, each request will take longer to fulfill.
29 |
30 |
31 |
32 |
33 |
"Omnibuser"? What?
34 |
35 | An omnibus is a bunch of short works by a particular author collected into a single book. This tool collects a bunch of serially-published chapters into a single ebook. It makes omnibuses. It's an omnibuser. Look, domain names are hard, okay?
36 |
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/public/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/books.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/books.jpg
--------------------------------------------------------------------------------
/public/images/error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/error.png
--------------------------------------------------------------------------------
/public/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/favicon.png
--------------------------------------------------------------------------------
/public/images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/github.png
--------------------------------------------------------------------------------
/public/images/header_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/header_logo.png
--------------------------------------------------------------------------------
/public/images/omnibuser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/omnibuser.png
--------------------------------------------------------------------------------
/public/images/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/public/images/twitter.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | User-agent: *
5 | Disallow: /documents
6 |
--------------------------------------------------------------------------------
/spec/factories/chapters.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :chapter do
3 | association :story
4 | sequence(:number) {|n| n}
5 | title {Faker::Superhero.name}
6 |
7 | factory :untitled_chapter do
8 | title nil
9 | end
10 |
11 | factory :chapter_with_images do
12 | content "
\n
"
13 | end
14 | factory :chapter_with_srcless_images do
15 | content "
\n
"
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/factories/documents.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :document do
3 | association :story
4 | filename 'generic_document'
5 | extension 'html'
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/images.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :image do
3 | cover false
4 | extension 'jpg'
5 |
6 | factory :cover_image do
7 | cover true
8 | end
9 |
10 | factory :gif do
11 | extension 'gif'
12 | end
13 | factory :png do
14 | extension 'png'
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/spec/factories/requests.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :request do
3 | url "https://www.fanfiction.net/s/5782108/"
4 | extension 'epub'
5 | strategy 'all'
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/factories/stories.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :story do
3 | association :request
4 | url "fanfiction.net/s/5782108/"
5 | title "Harry Potter and the Methods of Rationality"
6 | author "Less Wrong"
7 | meta_data "{\"summary\":\"Petunia married a biochemist, and Harry grew up reading science and science fiction. Then came the Hogwarts letter, and a world of intriguing new possibilities to exploit. And new friends, like Hermione Granger, and Professor McGonagall, and Professor Quirrell... COMPLETE.\",\"info\":\"Rated: Fiction T - English - Drama/Humor - Harry P., Hermione G. - Chapters: 122 - Words: 661,619 - Reviews: 32,985 - Favs: 20,340 - Follows: 16,184 - Updated: 3/14/2015 - Published: 2/28/2010 - Status: Complete - id: 5782108 \"}"
8 |
9 | factory :ffn_story do
10 | url "https://www.fanfiction.net"
11 | end
12 |
13 | factory :fp_story do
14 | url "https://www.fictionpress.com"
15 | end
16 |
17 | factory :sv_story do
18 | url "https://forums.sufficientvelocity.com"
19 | end
20 |
21 | factory :sb_story do
22 | url "https://forums.spacebattles.com"
23 | end
24 |
25 | factory :qq_story do
26 | url "https://forum.questionablequesting.com"
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/spec/features/fanfiction_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | feature "FanFiction", js: true do
4 | let(:single_chapter) {'https://www.fanfiction.net/s/3853/1/Lily-Fly-Away'}
5 | let(:multi_chapter) {'https://www.fanfiction.net/s/195487/1/Bill-and-Ted-s-Adventure'}
6 |
7 | before :each do
8 | visit root_path
9 | end
10 |
11 | scenario "Scraping a single-chapter story" do
12 | get_story single_chapter, extension: 'epub'
13 | expect(page).to have_content('Download')
14 | end
15 | scenario "Scraping all chapters from a multi-chapter story" do
16 | get_story multi_chapter, extension: 'html'
17 | expect(page).to have_content('Download')
18 | end
19 | scenario "Scraping one chapter from a multi-chapter story" do
20 | get_story multi_chapter, extension: 'mobi', recent: true, count: 1
21 | expect(page).to have_content('Download')
22 | end
23 | scenario "Scraping 10 chapters from a story with fewer than 10 chapters" do
24 | get_story multi_chapter, extension: 'pdf', recent: true, count: 10
25 | expect(page).to have_content('Download')
26 | end
27 | end
28 |
29 | feature "FictionPress", js: true do
30 | let(:single_chapter) {'https://www.fictionpress.com/s/3593/1/The-Secret-Valley'}
31 | let(:multi_chapter) {'https://www.fictionpress.com/s/2737883/1/Incapaz-de-querer'}
32 |
33 | before :each do
34 | visit root_path
35 | end
36 |
37 | scenario "Scraping a single-chapter story" do
38 | get_story single_chapter, extension: 'epub'
39 | expect(page).to have_content('Download')
40 | end
41 | scenario "Scraping all chapters from a multi-chapter story" do
42 | get_story multi_chapter, extension: 'html'
43 | expect(page).to have_content('Download')
44 | end
45 | scenario "Scraping one chapter from a multi-chapter story" do
46 | get_story multi_chapter, extension: 'mobi', recent: true, count: 1
47 | expect(page).to have_content('Download')
48 | end
49 | scenario "Scraping 10 chapters from a story with fewer than 10 chapters" do
50 | get_story multi_chapter, extension: 'pdf', recent: true, count: 10
51 | expect(page).to have_content('Download')
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/spec/features/forum_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | feature "SpaceBattles", js: true do
4 | let(:unthreadmarked_op) {'https://forums.spacebattles.com/threads/under-your-mask-gundam-iron-blooded-orphans.463801/'}
5 | let(:large_images) {'https://forums.spacebattles.com/threads/ydia-ii-wild-wasteland-a-fallout-ranma-sm-cross.388980/'}
6 |
7 | before :each do
8 | visit root_path
9 | end
10 |
11 | scenario "Scraping all chapters from a multi-chapter story" do
12 | get_story large_images, extension: 'html'
13 | expect(page).to have_content('Download')
14 | end
15 | scenario "Scraping one chapter from a multi-chapter story" do
16 | get_story large_images, extension: 'mobi', recent: true, count: 1
17 | expect(page).to have_content('Download')
18 | end
19 | scenario "Scraping 10 chapters from a story with fewer than 10 chapters" do
20 | get_story large_images, extension: 'pdf', recent: true, count: 10
21 | expect(page).to have_content('Download')
22 | end
23 | scenario "Scraping a story with no threadmark for first post" do
24 | get_story unthreadmarked_op, extension: 'epub'
25 | expect(page).to have_content('Download')
26 | end
27 | end
28 |
29 | feature "Sufficient Velocity", js: true do
30 | let(:single_chapter) {'https://forums.sufficientvelocity.com/threads/archive-of-random-snips.32557/'}
31 | let(:unthreadmarked_op) {'https://forums.sufficientvelocity.com/threads/erlk%C3%B6nig-worm-au.33429/'}
32 | let(:large_images) {'https://forums.sufficientvelocity.com/threads/a-daughters-dedication-kancolle.33211/'}
33 | let(:many_threadmarks) {'https://forums.sufficientvelocity.com/threads/mauling-snarks-worm.41471/'}
34 |
35 | before :each do
36 | visit root_path
37 | end
38 |
39 | # scenario "Scraping a single-chapter story" do
40 | # get_story single_chapter, extension: 'epub'
41 | # expect(page).to have_content('Download')
42 | # end
43 | scenario "Scraping all chapters from a multi-chapter story" do
44 | get_story large_images, extension: 'html'
45 | expect(page).to have_content('Download')
46 | end
47 | scenario "Scraping one chapter from a multi-chapter story" do
48 | get_story large_images, extension: 'mobi', recent: true, count: 1
49 | expect(page).to have_content('Download')
50 | end
51 | scenario "Scraping 10 chapters from a story with fewer than 10 chapters" do
52 | get_story large_images, extension: 'pdf', recent: true, count: 10
53 | expect(page).to have_content('Download', wait: 100)
54 | end
55 | scenario "Scraping a story with no threadmark for first post" do
56 | get_story unthreadmarked_op, extension: 'epub'
57 | expect(page).to have_content('Download')
58 | end
59 | # scenario "Scraping a story with many threadmarks" do
60 | # get_story many_threadmarks, extension: 'html'
61 | # expect(page).to have_content('Download')
62 | # end
63 | end
64 |
65 | feature "Questionable Questing", js: true do
66 | let(:unthreadmarked_op) {'https://forum.questionablequesting.com/threads/a-prophets-portents-misc-original.2904/'}
67 | let(:large_images) {'https://forum.questionablequesting.com/threads/spitfire-quest-worm-x-d-d-quest-thread-1.1464/'}
68 |
69 | before :each do
70 | visit root_path
71 | end
72 |
73 | scenario "Scraping all chapters from a multi-chapter story" do
74 | get_story large_images, extension: 'html'
75 | expect(page).to have_content('Download')
76 | end
77 | scenario "Scraping one chapter from a multi-chapter story" do
78 | get_story large_images, extension: 'mobi', recent: true, count: 1
79 | expect(page).to have_content('Download')
80 | end
81 | scenario "Scraping 10 chapters from a story with fewer than 10 chapters" do
82 | get_story large_images, extension: 'pdf', recent: true, count: 10
83 | expect(page).to have_content('Download', wait: 100)
84 | end
85 | scenario "Scraping a story with no threadmark for first post" do
86 | get_story unthreadmarked_op, extension: 'epub'
87 | expect(page).to have_content('Download')
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/spec/features/toc_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | feature "TOCScraper", js: true do
4 |
5 | before :each do
6 | visit root_path
7 | end
8 |
9 | scenario "Scraping last 3 chapters of Worm" do
10 | get_story 'https://parahumans.wordpress.com', extension: 'epub', recent: true, count: 3
11 | expect(page).to have_content('Download')
12 | end
13 |
14 | scenario "Scraping last 7 chapters of Unsong" do
15 | get_story 'https://unsongbook.com', extension: 'pdf', recent: true, count: 7
16 | expect(page).to have_content('Download')
17 | end
18 |
19 | scenario "Scraping last 3 chapters of Practical Guide To Evil" do
20 | get_story 'https://practicalguidetoevil.wordpress.com', extension: 'mobi', recent: true, count: 3
21 | expect(page).to have_content('Download')
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/spec/models/builders/doc_builder_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | require 'fileutils'
3 |
4 | describe DocBuilder do
5 | class TestBuilder < DocBuilder
6 | attr_accessor :template_dir, :directory
7 | end
8 |
9 | describe '#render_template' do
10 |
11 | before :all do
12 | @template_dir = '/tmp/test/template'
13 | @template = 'buildertest.erb'
14 | @directory = '/tmp/test/directory'
15 | @output = 'output'
16 | @template_path = "#{@template_dir}/#{@template}"
17 | @output_path = "#{@directory}/#{@output}"
18 | @doc = build(:document)
19 | builder = TestBuilder.new(doc: @doc,
20 | template_dir: @template_dir, directory: @directory)
21 | FileUtils.rm_r('/tmp/test') if Dir.exist?('/tmp/test')
22 | FileUtils.mkdir(['/tmp/test', @template_dir, @directory])
23 | File.open(@template_path, 'w+') do |f|
24 | f << "<%= @doc.story.title %>"
25 | end
26 | builder.render_template(@template, @output)
27 | end
28 |
29 | it "creates a new file at the output path" do
30 | expect(File.exist?(@output_path)).to be true
31 | end
32 | it "renders the template into the file as ERB" do
33 | expect(File.read(@output_path)).to eq(@doc.story.title)
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/spec/models/builders/html_builder_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe HTMLBuilder do
4 | before :all do
5 | @story = create(:story)
6 | @doc = Document.new(story_id: @story.id, filename: @story.title,
7 | extension: 'html')
8 | @doc.sanitize_filename
9 | 3.times {create(:chapter, story_id: @story.id)}
10 | FileUtils.rm_r("/tmp/#{@doc.filename}") if Dir.exist?("/tmp/#{@doc.filename}")
11 | @builder = HTMLBuilder.new(doc: @doc)
12 | @builder.template_dir = Rails.root.join("app", "templates", 'html')
13 | @builder.domain = @story.domain
14 | @builder.create_directory_structure
15 | end
16 |
17 | after :all do
18 | FileUtils.rm_r("/tmp/#{@doc.filename}") if Dir.exist?("/tmp/#{@doc.filename}")
19 |
20 | File.delete("/tmp/#{@doc.filename}.zip") if File.exist?("/tmp/#{@doc.filename}.zip")
21 | end
22 |
23 | describe '#build' do
24 | after :each do
25 | allow_any_instance_of(HTMLBuilder).to receive :zip_directory
26 | @builder.build
27 | end
28 | it "sets @domain" do
29 | allow_any_instance_of(HTMLBuilder).to receive :zip_directory
30 | @builder.domain = nil
31 | @builder.build
32 | expect(@builder.domain).to eq @story.domain
33 | end
34 | it "creates directory structure" do
35 | expect_any_instance_of(HTMLBuilder).to receive :create_directory_structure
36 | end
37 | it "adds style files" do
38 | expect_any_instance_of(HTMLBuilder).to receive :add_styles
39 | end
40 | it "adds cover image" do
41 | expect_any_instance_of(HTMLBuilder).to receive :create_cover
42 | end
43 | it "adds other images" do
44 | expect_any_instance_of(HTMLBuilder).to receive :add_images
45 | end
46 | it "adds story file" do
47 | expect_any_instance_of(HTMLBuilder).to receive :create_story
48 | end
49 | context "nozip is true" do
50 | it "returns the path to main story file" do
51 | expect(@builder.build(nozip: true)).to eq("/tmp/#{@doc.filename}/story.html")
52 | end
53 | end
54 | context "nozip is false" do
55 | it "zips the directory" do
56 | expect_any_instance_of(HTMLBuilder).to receive :zip_directory
57 | end
58 | end
59 | end
60 | describe '#create_directory_structure' do
61 | it "removes previous directory if it exists" do
62 | expect{@builder.create_directory_structure}.not_to raise_error
63 | end
64 | it "creates directory in /tmp named with doc filename" do
65 | expect(Dir.exist?("/tmp/#{@doc.filename}")).to be true
66 | end
67 | it "creates files subdir" do
68 | expect(Dir.exist?("/tmp/#{@doc.filename}/files")).to be true
69 | end
70 | it "creates styles subdir" do
71 | expect(Dir.exist?("/tmp/#{@doc.filename}/files/css")).to be true
72 | end
73 | it "creates images subdir" do
74 | expect(Dir.exist?("/tmp/#{@doc.filename}/files/images")).to be true
75 | end
76 | end
77 | describe '#add_styles' do
78 | before :each do
79 | @builder.domain = 'ffn'
80 | @builder.add_styles
81 | end
82 | it "adds the main css file to the folder" do
83 | expect(File.exist?("/tmp/#{@doc.filename}/files/css/main.css")).to be true
84 | end
85 | it "adds the domain specific css file to the folder" do
86 | expect(File.exist?("/tmp/#{@doc.filename}/files/css/#{@builder.domain}.css")).to be true
87 | end
88 | end
89 | describe "image handling", speed: 'slow' do
90 | before :all do
91 | @cover = create(:image, story_id: @story.id, source_url: 'url1', cover: true)
92 | @image = create(:png, story_id: @story.id, source_url: 'url2')
93 | FileUtils.cp(Rails.root.join("spec", "support", "images", "dice.png"),
94 | "#{@image.path}.temp")
95 | FileUtils.cp(Rails.root.join("spec", "support", "images", "lake.jpg"),
96 | "#{@cover.path}.temp")
97 | @cover.compress
98 | @image.compress
99 | @cover.upload
100 | @image.upload
101 | @builder.add_images
102 | end
103 | describe '#add_images' do
104 | it "downloads images to images subdir" do
105 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/#{@image.name}")).to be true
106 | end
107 | it "only applies to images which are not a cover" do
108 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/#{@cover.name}")).not_to be true
109 | end
110 | context "domain is sb or sv" do
111 | it "copies the smilies image to images subdir" do
112 | @builder.domain = 'sv'
113 | @builder.add_images
114 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/xenforo-smilies-sprite.png")).to be true
115 | File.delete("/tmp/#{@doc.filename}/files/images/xenforo-smilies-sprite.png")
116 | end
117 | end
118 | context "domain is not sb or sv" do
119 | it "does not copy the smilies image to images subdir" do
120 | @builder.domain = 'ffn'
121 | @builder.add_images
122 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/xenforo-smilies-sprite.png")).to be false
123 | end
124 | end
125 | end
126 |
127 | describe '#create_cover' do
128 | context "story has a cover image" do
129 | it "downloads cover image to images subdir" do
130 | @builder.create_cover
131 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/#{@cover.name}")).to be true
132 | end
133 | end
134 | context "story does not have a cover image" do
135 | before :all do
136 | @story.images.delete_all
137 | end
138 | it "copies the domain specific placeholder image to images subdir" do
139 | @builder.create_cover
140 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/#{@builder.domain}.png")).to be true
141 | end
142 | it "defaults to the omnibuser favicon if no domain is specified" do
143 | @builder.domain = nil
144 | @builder.create_cover
145 | expect(File.exist?("/tmp/#{@doc.filename}/files/images/favicon.png")).to be true
146 | end
147 | end
148 | end
149 | end
150 |
151 | describe '#create_story' do
152 | it "creates the story file" do
153 | @builder.create_story
154 | expect(File.exist?("/tmp/#{@doc.filename}/story.html")).to be true
155 | end
156 | end
157 | describe '#zip_directory' do
158 | it "creates a new zip file with the doc filename and zip extension" do
159 | File.delete("/tmp/#{@doc.filename}.zip") if File.exist?("/tmp/#{@doc.filename}.zip")
160 | @builder.input = []
161 | @builder.zip_directory
162 | expect(File.exist?("/tmp/#{@doc.filename}.zip")).to be true
163 | end
164 | end
165 | end
166 |
--------------------------------------------------------------------------------
/spec/models/builders/mobi_builder_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe MOBIBuilder do
4 | before :all do
5 | @story = create(:story)
6 | @doc = Document.new(story_id: @story.id, filename: @story.title,
7 | extension: 'mobi')
8 | @doc.sanitize_filename
9 | 3.times {create(:chapter, story_id: @story.id)}
10 | FileUtils.rm_r("/tmp/#{@doc.filename}") if Dir.exist?("/tmp/#{@doc.filename}")
11 | @builder = MOBIBuilder.new(doc: @doc)
12 | @builder.build
13 | end
14 |
15 | after :all do
16 | FileUtils.rm_r("/tmp/#{@doc.filename}") if Dir.exist?("/tmp/#{@doc.filename}")
17 |
18 | File.delete("/tmp/#{@doc.filename}.epub") if File.exist?("/tmp/#{@doc.filename}.epub")
19 |
20 | File.delete("/tmp/#{@doc.filename}.mobi") if File.exist?("/tmp/#{@doc.filename}.mobi")
21 | end
22 |
23 | describe '#build' do
24 | it "builds an epub of the doc" do
25 | expect(File.exist?("/tmp/#{@doc.filename}.epub")).to be true
26 | end
27 | it "converts to mobi" do
28 | expect(File.exist?("/tmp/#{@doc.filename}.mobi")).to be true
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/spec/models/builders/pdf_builder_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe PDFBuilder do
4 | before :all do
5 | @story = create(:story)
6 | @doc = Document.new(story_id: @story.id, filename: @story.title,
7 | extension: 'pdf')
8 | @doc.sanitize_filename
9 | 30.times {create(:chapter, story_id: @story.id)}
10 | FileUtils.rm_r("/tmp/#{@doc.filename}") if Dir.exist?("/tmp/#{@doc.filename}")
11 | @builder = PDFBuilder.new(doc: @doc)
12 | @builder.template_dir = Rails.root.join("app", "templates", 'html')
13 | @builder.domain = @story.domain
14 | @builder.create_directory_structure
15 | end
16 |
17 | after :all do
18 | FileUtils.rm_r("/tmp/#{@doc.filename}") if Dir.exist?("/tmp/#{@doc.filename}")
19 |
20 | File.delete("/tmp/#{@doc.filename}.pdf") if File.exist?("/tmp/#{@doc.filename}.pdf")
21 | end
22 |
23 | describe '#build' do
24 | after :each do
25 | allow_any_instance_of(PDFBuilder).to receive :convert_to_pdf
26 | allow_any_instance_of(PDFBuilder).to receive :combine_pdfs
27 | @builder.build
28 | end
29 | it "sets @domain" do
30 | allow_any_instance_of(PDFBuilder).to receive :convert_to_pdf
31 | allow_any_instance_of(PDFBuilder).to receive :combine_pdfs
32 | @builder.domain = nil
33 | @builder.build
34 | expect(@builder.domain).to eq @story.domain
35 | end
36 | it "creates directory structure" do
37 | expect_any_instance_of(PDFBuilder).to receive :create_directory_structure
38 | end
39 | it "adds styles" do
40 | expect_any_instance_of(PDFBuilder).to receive :add_styles
41 | end
42 | it "adds cover" do
43 | expect_any_instance_of(PDFBuilder).to receive :create_cover
44 | end
45 | it "adds images" do
46 | expect_any_instance_of(PDFBuilder).to receive :add_images
47 | end
48 | it "adds frontmatter" do
49 | expect_any_instance_of(PDFBuilder).to receive :create_frontmatter
50 | end
51 | it "adds content" do
52 | expect_any_instance_of(PDFBuilder).to receive :create_content
53 | end
54 | it "copies filler file" do
55 | expect(File.exist?("/tmp/#{@doc.filename}/filler.html")).to be true
56 | end
57 | it "converts to pdf" do
58 | expect_any_instance_of(PDFBuilder).to receive :convert_to_pdf
59 | end
60 | it "combines pdfs" do
61 | expect_any_instance_of(PDFBuilder).to receive :combine_pdfs
62 | end
63 | end
64 | describe '#create_frontmatter' do
65 | it "creates frontmatter file" do
66 | @builder.create_frontmatter
67 | expect(File.exist?("/tmp/#{@doc.filename}/frontmatter.html")).to be true
68 | end
69 | end
70 | describe '#create_content' do
71 | it "creates a html file for each 10 chapters" do
72 | @builder.create_content
73 | expect(File.exist?("/tmp/#{@doc.filename}/content_1.html")).to be true
74 | expect(File.exist?("/tmp/#{@doc.filename}/content_2.html")).to be true
75 | expect(File.exist?("/tmp/#{@doc.filename}/content_3.html")).to be true
76 | expect(File.exist?("/tmp/#{@doc.filename}/content_4.html")).to be false
77 | end
78 | end
79 | describe "pdf creation" do
80 | before :all do
81 | @builder.create_frontmatter
82 | @builder.create_content
83 | @builder.render_template('../pdf/filler.html.erb', 'filler.html')
84 | @builder.convert_to_pdf
85 | end
86 | describe '#convert_to_pdf' do
87 | it "creates a pdf for each file in @files" do
88 | expect(File.exist?("/tmp/#{@doc.filename}/content_1.pdf")).to be true
89 | expect(File.exist?("/tmp/#{@doc.filename}/content_2.pdf")).to be true
90 | expect(File.exist?("/tmp/#{@doc.filename}/content_3.pdf")).to be true
91 | expect(File.exist?("/tmp/#{@doc.filename}/frontmatter.pdf")).to be true
92 | end
93 | end
94 | describe '#combine_pdfs' do
95 | it "creates a new pdf at the doc path" do
96 | @builder.combine_pdfs
97 | expect(File.exist?("/tmp/#{@doc.filename}.pdf")).to be true
98 | end
99 | end
100 | end
101 |
102 | end
103 |
--------------------------------------------------------------------------------
/spec/models/chapter_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Chapter do
4 | it { should belong_to(:story) }
5 | it { should validate_uniqueness_of(:number).scoped_to(:story_id) }
6 |
7 | describe '#ensure_title' do
8 | it "updates record with default title if title is blank" do
9 | chapter = create(:untitled_chapter)
10 | expect(chapter.title).to eq("Chapter #{chapter.number}")
11 | end
12 | it "does not change title if title is not blank" do
13 | chapter = create(:chapter, title: "Awesome Chapter")
14 | expect(chapter.title).to eq("Awesome Chapter")
15 | end
16 | end
17 |
18 | describe '#epub' do
19 | it "changes image src's to include correct path" do
20 | chapter = create(:chapter_with_images)
21 | expect(chapter.epub).to eq "
\n
"
22 | end
23 | end
24 |
25 | describe '#html' do
26 | it "changes image src's to include correct path" do
27 | chapter = create(:chapter_with_images)
28 | expect(chapter.html).to eq "
\n
"
29 | end
30 | it "does not alter image src if src is blank" do
31 | chapter = create(:chapter_with_srcless_images)
32 | expect(chapter.html).to eq "
\n
"
33 | end
34 | end
35 |
36 | describe '#xhtml' do
37 | it "returns a Nokogiri nodeset" do
38 | chapter = create(:chapter_with_images)
39 | expect(chapter.xhtml).to be_an_instance_of Nokogiri::XML::Document
40 | end
41 | end
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/spec/models/document_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Document do
4 | it { should belong_to(:story) }
5 |
6 | describe '#sanitize_filename' do
7 | before :each do
8 | allow_any_instance_of(Document).to receive(:add_chapter_numbers).and_return("cnums added")
9 | @doc = build(:document, filename: 'ad-hoc')
10 | end
11 | it "replaces non-alphanumeric characters with underscores" do
12 | expect(build_doc_with_name('ad-hoc').filename).to eq('ad_hoc')
13 | end
14 | it "does not have consecutive underscores" do
15 | expect(build_doc_with_name('ad--hoc').filename).to eq('ad_hoc')
16 | end
17 | it "does not have leading underscores" do
18 | expect(build_doc_with_name('-ad-hoc').filename).to eq('ad_hoc')
19 | end
20 | it "does not have trailing underscores" do
21 | expect(build_doc_with_name('ad-hoc-').filename).to eq('ad_hoc')
22 | end
23 | it "is shorter than 230 characters" do
24 | expect(build_doc_with_name('a'*300).filename.length).to be <= 230
25 | end
26 | it "adds chapter range if recent strategy was used" do
27 | @doc.story.request.update strategy: 'recent'
28 | expect(@doc.sanitize_filename).to eq 'cnums added'
29 | end
30 | it "does not add chapter range if recent strategy was not used" do
31 | @doc.story.request.update strategy: 'all'
32 | expect(@doc.sanitize_filename).not_to eq 'cnums added'
33 | end
34 | end
35 |
36 | describe '#add_chapter_numbers' do
37 | before :all do
38 | FactoryGirl.reload
39 | @story = create(:ffn_story)
40 | create(:chapter, story_id: @story.id)
41 | end
42 | it "only adds a single number if there is only one chapter" do
43 | doc = build(:document, story_id: @story.id, filename: 'single')
44 | doc.add_chapter_numbers
45 | expect(doc.filename).to eq('single_1')
46 | end
47 | it "adds first and last chapter numbers if more than one chapter" do
48 | create(:chapter, story_id: @story.id)
49 | create(:chapter, story_id: @story.id)
50 | doc = build(:document, story_id: @story.id, filename: 'multiple')
51 | doc.add_chapter_numbers
52 | expect(doc.filename).to eq('multiple_1-3')
53 | end
54 | end
55 |
56 | describe '#path' do
57 | it "returns doc's path" do
58 | doc = build(:document)
59 | expect(doc.path).to eq("/tmp/#{doc.filename}.#{doc.extension}")
60 | end
61 | end
62 |
63 | describe '#delete_file' do
64 | it "deletes the doc file if it exists" do
65 | doc = build(:document)
66 | FileUtils.touch(doc.path)
67 | expect(File.exist?(doc.path)).to be true
68 | doc.delete_file
69 | expect(File.exist?(doc.path)).to be false
70 | end
71 | it "returns nil if doc file does not exist" do
72 | doc = build(:document)
73 | expect(doc.delete_file).to be nil
74 | end
75 | end
76 |
77 | describe '#build' do
78 | before :each do
79 | allow_any_instance_of(PDFBuilder).to receive(:build)
80 | allow_any_instance_of(HTMLBuilder).to receive(:build)
81 | allow_any_instance_of(MOBIBuilder).to receive(:build)
82 | allow_any_instance_of(EPUBBuilder).to receive(:build)
83 | allow_any_instance_of(Document).to receive(:upload)
84 | end
85 | it "instantiates PDFBuilder if extension is pdf" do
86 | expect(PDFBuilder).to receive_message_chain(:new, :build)
87 | build(:document, extension: 'pdf').build
88 | end
89 | it "instantiates HTMLBuilder if extension is html" do
90 | expect(HTMLBuilder).to receive_message_chain(:new, :build)
91 | build(:document, extension: 'html').build
92 | end
93 | it "instantiates MOBIBuilder if extension is mobi" do
94 | expect(MOBIBuilder).to receive_message_chain(:new, :build)
95 | build(:document, extension: 'mobi').build
96 | end
97 | it "instantiates EPUBBuilder if extension is epub" do
98 | expect(EPUBBuilder).to receive_message_chain(:new, :build)
99 | build(:document, extension: 'epub').build
100 | end
101 | it "changes extension to zip if it is html" do
102 | doc = build(:document, extension: 'html')
103 | doc.build
104 | expect(doc.extension).to eq 'zip'
105 | end
106 | it "uploads after building" do
107 | doc = build(:document, extension: 'html')
108 | expect(doc).to receive(:upload)
109 | doc.build
110 | end
111 | end
112 |
113 | describe '#upload' do
114 | before :each do
115 | allow_any_instance_of(Document).to receive(:build)
116 | @doc = create(:document)
117 | FileUtils.touch(@doc.path)
118 | @aws_object = S3_BUCKET.objects["documents/#{@doc.id}/#{@doc.filename}.#{@doc.extension}"]
119 | @doc.upload
120 | end
121 | it "uploads document to documents folder on AWS" do
122 | expect(@aws_object.exists?).to be true
123 | end
124 | it "updates document record with AWS url and key" do
125 | expect(@doc.aws_url).to eq(@aws_object.public_url.to_s)
126 | expect(@doc.aws_key).to eq(@aws_object.key)
127 | end
128 | end
129 | end
130 |
--------------------------------------------------------------------------------
/spec/models/image_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 | include Colorscore
3 |
4 | describe Image do
5 | it { should belong_to(:story) }
6 |
7 | before :all do
8 | @story = create(:story)
9 | @jpg = create(:image, story_id: @story.id, source_url: 'url1')
10 | @gif = create(:gif, story_id: @story.id, source_url: 'url2')
11 | @png = create(:png, story_id: @story.id, source_url: 'url3')
12 | FileUtils.cp(Rails.root.join("spec", "support", "images", "dancing_banana.gif"),
13 | "#{@gif.path}.temp")
14 | @gif.compress
15 | FileUtils.cp(Rails.root.join("spec", "support", "images", "lake.jpg"),
16 | "#{@jpg.path}.temp")
17 | @jpg.compress
18 | end
19 |
20 | describe '#generate_name' do
21 | it "generates a random filename" do
22 | expect(@jpg.filename).not_to eq(@png.filename)
23 | end
24 | end
25 |
26 | describe '#name' do
27 | it "gives its own filename with extension" do
28 | expect(@jpg.name).to eq("#{@jpg.filename}.#{@jpg.extension}")
29 | end
30 | end
31 |
32 | describe '#path' do
33 | it "gives its path on the filesystem" do
34 | expect(@jpg.path).to eq("/tmp/#{@jpg.name}")
35 | end
36 | end
37 |
38 | describe '#compress' do
39 | context "gifs" do
40 | it "saves output to correct path" do
41 | expect(File.exist?(@gif.path)).to be true
42 | end
43 | it "compresses output" do
44 | expect(File.size(@gif.path)).to be < File.size("#{@gif.path}.temp")
45 | end
46 | end
47 |
48 | context "non-gif" do
49 | context 'png' do
50 | before :all do
51 | @white_png = @png
52 | @black_png = create(:png, story_id: @story.id)
53 | FileUtils.cp(Rails.root.join("spec", "support", "images", "dice.png"),
54 | "#{@black_png.path}.temp")
55 | FileUtils.cp(Rails.root.join("spec", "support", "images", "dice.png"),
56 | "#{@white_png.path}.temp")
57 | @white_png.compress
58 | @black_png.compress('#000000')
59 | end
60 |
61 | it "replaces alpha in png with user provided background color" do
62 | expect(Histogram.new(@black_png.path).scores.first[1].hex).to match('000000')
63 | end
64 |
65 | it "defaults background color to white" do
66 | expect(Histogram.new(@white_png.path).scores.first[1].hex).to match('ffffff')
67 | end
68 |
69 | it "converts to jpg" do
70 | expect(MiniMagick::Image.open(@white_png.path).data['mimeType']).to eq('image/jpeg')
71 | end
72 |
73 | it "updates extension to jpg" do
74 | expect(@white_png.extension).to eq('jpg')
75 | end
76 | end
77 | it "limits width to 1000px while maintaining aspect ratio" do
78 | expect(MiniMagick::Image.open(@jpg.path).data['geometry']['width']).to eq(1000)
79 | expect(MiniMagick::Image.open(@jpg.path).data['geometry']['height']).to eq(750)
80 | end
81 | it "compresses file" do
82 | expect(File.size(@jpg.path)).to be < File.size("#{@jpg.path}.temp")
83 | end
84 | it "saves file to correct path" do
85 | expect(@jpg.path).to eq("/tmp/#{@jpg.filename}.jpg")
86 | end
87 | end
88 | end
89 |
90 | describe 'AWS interactions', type: 'aws', speed: 'slow' do
91 | before :all do
92 | @aws_object = S3_BUCKET.objects["images/#{@jpg.name}"]
93 | @jpg.upload
94 | end
95 | describe '#upload' do
96 | it "uploads image to images folder on AWS" do
97 | expect(@aws_object.exists?).to be true
98 | end
99 | it "updates image record with AWS url and key" do
100 | expect(@jpg.aws_url).to eq(@aws_object.public_url.to_s)
101 | expect(@jpg.aws_key).to eq(@aws_object.key)
102 | end
103 | end
104 |
105 | describe '#download' do
106 | before :all do
107 | File.delete(@jpg.path)
108 | @download = @jpg.download
109 | end
110 | it "downloads image from AWS" do
111 | expect(File.exist?(@jpg.path)).to be true
112 | end
113 | it "saves to specified dir if provided" do
114 | Dir.mkdir('/tmp/test') unless Dir.exist?('/tmp/test')
115 | @jpg.download('/tmp/test')
116 | expect(File.exist?("/tmp/test/#{@jpg.name}")).to be true
117 | end
118 | it "returns path to file" do
119 | expect(@download).to eq(@jpg.path)
120 | end
121 | end
122 | end
123 | end
124 |
--------------------------------------------------------------------------------
/spec/models/request_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Request do
4 | it { should belong_to(:story) }
5 | end
6 |
--------------------------------------------------------------------------------
/spec/models/story_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | describe Story do
4 | it { should have_many(:chapters).dependent(:destroy) }
5 | it { should have_many(:documents).dependent(:destroy) }
6 | it { should have_many(:images).dependent(:destroy) }
7 | it { should have_one(:request) }
8 |
9 | before :all do
10 | @story = create(:story)
11 | @image1 = create(:image, story_id: @story.id, source_url: 'url1')
12 | @image2 = create(:image, story_id: @story.id, source_url: 'url2')
13 | @cover_image = create(:cover_image, story_id: @story.id, source_url: 'url2')
14 | @smilies = create(:image, story_id: @story.id, source_url: 'styles/sv_smiles')
15 | end
16 |
17 | describe '#build' do
18 | before :each do
19 | allow_any_instance_of(Document).to receive(:build)
20 | allow_any_instance_of(Document).to receive(:sanitize_filename)
21 | end
22 |
23 | it "creates a Document" do
24 | expect{@story.build('html')}.to change(Document, :count).by(1)
25 | end
26 |
27 | it "sets Document attributes correctly" do
28 | document = Document.find(@story.build('html'))
29 | expect(document.story_id).to eq(@story.id)
30 | expect(document.filename).to eq(@story.title)
31 | expect(document.extension).to eq('html')
32 | end
33 |
34 | it "returns the doc id" do
35 | expect(@story.build('html')).to eq(Document.last.id)
36 | end
37 | end
38 |
39 | describe '#cover_image' do
40 | it "returns the cover image" do
41 | expect(@story.cover_image).to eq(@cover_image)
42 | end
43 | end
44 | describe '#has_image' do
45 | it "returns the image at specified url" do
46 | expect(@story.has_image('url1')).to eq(@image1)
47 | end
48 | it "does not return a cover image" do
49 | expect(@story.has_image('url2')).to eq(@image2)
50 | end
51 | it "returns nil if no match found" do
52 | expect(@story.has_image('url3')).to be_nil
53 | end
54 | end
55 |
56 | describe '#add_domain' do
57 | it "sets domain based on url" do
58 | expect(create(:ffn_story).domain).to eq('ffn')
59 | expect(create(:fp_story).domain).to eq('fp')
60 | expect(create(:sv_story).domain).to eq('sv')
61 | expect(create(:sb_story).domain).to eq('sb')
62 | expect(create(:qq_story).domain).to eq('qq')
63 | expect(create(:story, url: 'bad_url').domain).to be_nil
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | ENV['RAILS_ENV'] ||= 'test'
3 | require File.expand_path('../../config/environment', __FILE__)
4 | # Prevent database truncation if the environment is production
5 | abort("The Rails environment is running in production mode!") if Rails.env.production?
6 | require 'spec_helper'
7 | require 'rspec/rails'
8 | require 'capybara/rails'
9 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
10 |
11 | # Add additional requires below this line. Rails is not loaded until this point!
12 |
13 | # Requires supporting ruby files with custom matchers and macros, etc, in
14 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
15 | # run as spec files by default. This means that files in spec/support that end
16 | # in _spec.rb will both be required and run as specs, causing the specs to be
17 | # run twice. It is recommended that you do not name files matching this glob to
18 | # end with _spec.rb. You can configure this pattern with the --pattern
19 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
20 | #
21 | # The following line is provided for convenience purposes. It has the downside
22 | # of increasing the boot-up time by auto-requiring all files in the support
23 | # directory. Alternatively, in the individual `*_spec.rb` files, manually
24 | # require only the support files necessary.
25 | #
26 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
27 |
28 | # Checks for pending migration and applies them before tests are run.
29 | # If you are not using ActiveRecord, you can remove this line.
30 | ActiveRecord::Migration.maintain_test_schema!
31 |
32 | Shoulda::Matchers.configure do |config|
33 | config.integrate do |with|
34 | with.test_framework :rspec
35 | with.library :rails
36 | end
37 | end
38 |
39 | RSpec.configure do |config|
40 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
41 | #config.fixture_path = "#{::Rails.root}/spec/fixtures"
42 | config.include FactoryGirl::Syntax::Methods
43 | config.include DocumentMacros
44 | config.include FormMacros
45 |
46 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
47 | # examples within a transaction, remove the following line or assign false
48 | # instead of true.
49 | config.use_transactional_fixtures = true
50 |
51 | # RSpec Rails can automatically mix in different behaviours to your tests
52 | # based on their file location, for example enabling you to call `get` and
53 | # `post` in specs under `spec/controllers`.
54 | #
55 | # You can disable this behaviour by removing the line below, and instead
56 | # explicitly tag your specs with their type, e.g.:
57 | #
58 | # RSpec.describe UsersController, :type => :controller do
59 | # # ...
60 | # end
61 | #
62 | # The different available types are documented in the features, such as in
63 | # https://relishapp.com/rspec/rspec-rails/docs
64 | config.infer_spec_type_from_file_location!
65 |
66 | # Filter lines from Rails gems in backtraces.
67 | config.filter_rails_from_backtrace!
68 | # arbitrary gems may also be filtered via:
69 | # config.filter_gems_from_backtrace("gem name")
70 | end
71 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'capybara/rspec'
2 |
3 | ENV['RAILS_ENV'] ||= 'test'
4 |
5 | Capybara.register_driver :chrome do |app|
6 | Selenium::WebDriver::Chrome.driver_path = "/usr/bin/chromedriver"
7 | Capybara::Selenium::Driver.new(app, browser: :chrome)
8 | end
9 |
10 | Capybara.javascript_driver = :chrome
11 | Capybara.app_host = 'http://localhost:3000'
12 | Capybara.server_host = "localhost"
13 | Capybara.server_port = "3001"
14 | Capybara.default_max_wait_time = 300
15 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all
16 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
17 | # The generated `.rspec` file contains `--require spec_helper` which will cause
18 | # this file to always be loaded, without a need to explicitly require it in any
19 | # files.
20 | #
21 | # Given that it is always loaded, you are encouraged to keep this file as
22 | # light-weight as possible. Requiring heavyweight dependencies from this file
23 | # will add to the boot time of your test suite on EVERY test run, even for an
24 | # individual file that may not need all of that loaded. Instead, consider making
25 | # a separate helper file that requires the additional dependencies and performs
26 | # the additional setup, and require it from the spec files that actually need
27 | # it.
28 | #
29 | # The `.rspec` file also contains a few flags that are not defaults but that
30 | # users commonly want.
31 | #
32 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
33 | RSpec.configure do |config|
34 |
35 | config.before(:suite) do
36 | Rails.application.load_seed
37 | end
38 | # rspec-expectations config goes here. You can use an alternate
39 | # assertion/expectation library such as wrong or the stdlib/minitest
40 | # assertions if you prefer.
41 | config.expect_with :rspec do |expectations|
42 | # This option will default to `true` in RSpec 4. It makes the `description`
43 | # and `failure_message` of custom matchers include text for helper methods
44 | # defined using `chain`, e.g.:
45 | # be_bigger_than(2).and_smaller_than(4).description
46 | # # => "be bigger than 2 and smaller than 4"
47 | # ...rather than:
48 | # # => "be bigger than 2"
49 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
50 | end
51 |
52 | # rspec-mocks config goes here. You can use an alternate test double
53 | # library (such as bogus or mocha) by changing the `mock_with` option here.
54 | config.mock_with :rspec do |mocks|
55 | # Prevents you from mocking or stubbing a method that does not exist on
56 | # a real object. This is generally recommended, and will default to
57 | # `true` in RSpec 4.
58 | mocks.verify_partial_doubles = true
59 | end
60 |
61 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
62 | # have no way to turn it off -- the option exists only for backwards
63 | # compatibility in RSpec 3). It causes shared context metadata to be
64 | # inherited by the metadata hash of host groups and examples, rather than
65 | # triggering implicit auto-inclusion in groups with matching metadata.
66 | config.shared_context_metadata_behavior = :apply_to_host_groups
67 |
68 | # The settings below are suggested to provide a good initial experience
69 | # with RSpec, but feel free to customize to your heart's content.
70 | =begin
71 | # This allows you to limit a spec run to individual examples or groups
72 | # you care about by tagging them with `:focus` metadata. When nothing
73 | # is tagged with `:focus`, all examples get run. RSpec also provides
74 | # aliases for `it`, `describe`, and `context` that include `:focus`
75 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
76 | config.filter_run_when_matching :focus
77 |
78 | # Allows RSpec to persist some state between runs in order to support
79 | # the `--only-failures` and `--next-failure` CLI options. We recommend
80 | # you configure your source control system to ignore this file.
81 | config.example_status_persistence_file_path = "spec/examples.txt"
82 |
83 | # Limits the available syntax to the non-monkey patched syntax that is
84 | # recommended. For more details, see:
85 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
86 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
87 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
88 | config.disable_monkey_patching!
89 |
90 | # Many RSpec users commonly either run the entire suite or an individual
91 | # file, and it's useful to allow more verbose output when running an
92 | # individual spec file.
93 | if config.files_to_run.one?
94 | # Use the documentation formatter for detailed output,
95 | # unless a formatter has already been configured
96 | # (e.g. via a command-line flag).
97 | config.default_formatter = 'doc'
98 | end
99 |
100 | # Print the 10 slowest examples and example groups at the
101 | # end of the spec run, to help surface which specs are running
102 | # particularly slow.
103 | config.profile_examples = 10
104 |
105 | # Run specs in random order to surface order dependencies. If you find an
106 | # order dependency and want to debug it, you can fix the order by providing
107 | # the seed, which is printed after each run.
108 | # --seed 1234
109 | config.order = :random
110 |
111 | # Seed global randomization in this process using the `--seed` CLI option.
112 | # Setting this allows you to use `--seed` to deterministically reproduce
113 | # test failures related to randomization by passing the same `--seed` value
114 | # as the one that triggered the failure.
115 | Kernel.srand config.seed
116 | =end
117 | end
118 |
119 | module FormatterOverrides
120 | def dump_pending(_)
121 | end
122 | end
123 |
124 | RSpec::Core::Formatters::DocumentationFormatter.prepend FormatterOverrides
125 |
--------------------------------------------------------------------------------
/spec/support/document_macros.rb:
--------------------------------------------------------------------------------
1 | module DocumentMacros
2 | def build_doc_with_name(name)
3 | doc = build(:document, filename: name)
4 | doc.sanitize_filename
5 | doc
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/support/form_macros.rb:
--------------------------------------------------------------------------------
1 | module FormMacros
2 | def get_story(url, recent: false, extension: nil, count: nil)
3 | fill_in('q', with: url)
4 | recent ? choose('Get most recent') : choose('Get all chapters')
5 | select extension, from: 'ext' if extension
6 | select count, from: 'recent_number' if count
7 | click_button 'Get'
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/support/images/dancing_banana.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/spec/support/images/dancing_banana.gif
--------------------------------------------------------------------------------
/spec/support/images/dice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/spec/support/images/dice.png
--------------------------------------------------------------------------------
/spec/support/images/lake.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/spec/support/images/lake.jpg
--------------------------------------------------------------------------------
/tmp/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/tmp/.keep
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/valedan/omnibuser/c413b67562b07974f7296b5d82a8efb95ee4ac3b/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------