spree-faq 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.hound.yml +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +11 -0
  6. data/CONTRIBUTING.md +30 -0
  7. data/Gemfile +6 -0
  8. data/Guardfile +8 -0
  9. data/LICENSE.md +26 -0
  10. data/README.md +37 -0
  11. data/Rakefile +15 -0
  12. data/app/assets/javascripts/admin/spree_faq.js.coffee +23 -0
  13. data/app/assets/javascripts/store/spree_faq.js.coffee +10 -0
  14. data/app/assets/stylesheets/admin/spree_faq.css +3 -0
  15. data/app/assets/stylesheets/store/spree_faq.css.scss +18 -0
  16. data/app/controllers/spree/admin/question_categories_controller.rb +13 -0
  17. data/app/controllers/spree/faqs_controller.rb +13 -0
  18. data/app/models/spree/question.rb +7 -0
  19. data/app/models/spree/question_category.rb +9 -0
  20. data/app/overrides/add_faq_admin_tab.rb +5 -0
  21. data/app/views/spree/admin/question_categories/_question.html.erb +14 -0
  22. data/app/views/spree/admin/question_categories/edit.html.erb +38 -0
  23. data/app/views/spree/admin/question_categories/index.html.erb +48 -0
  24. data/app/views/spree/admin/question_categories/new.html.erb +19 -0
  25. data/app/views/spree/admin/question_categories/new.js.erb +2 -0
  26. data/app/views/spree/faqs/index.html.erb +29 -0
  27. data/config/locales/en.yml +22 -0
  28. data/config/locales/sv.yml +22 -0
  29. data/config/routes.rb +6 -0
  30. data/db/migrate/20090526213535_create_questions.rb +16 -0
  31. data/db/migrate/20090526213550_create_question_categories.rb +14 -0
  32. data/db/migrate/20140331032743_rename_questions_to_spree_questions.rb +5 -0
  33. data/db/migrate/20140331032751_rename_question_categories_to_spree_question_categories.rb +5 -0
  34. data/lib/generators/spree_faq/install/install_generator.rb +30 -0
  35. data/lib/spree_faq/engine.rb +21 -0
  36. data/lib/spree_faq/version.rb +16 -0
  37. data/lib/spree_faq.rb +4 -0
  38. data/script/rails +7 -0
  39. data/spec/controllers/admin/question_categories_controller_spec.rb +67 -0
  40. data/spec/controllers/faqs_controller_spec.rb +29 -0
  41. data/spec/factories/question_category_factory.rb +5 -0
  42. data/spec/factories/question_factory.rb +7 -0
  43. data/spec/features/admin/faq_spec.rb +67 -0
  44. data/spec/features/faq_spec.rb +30 -0
  45. data/spec/models/question_category_spec.rb +50 -0
  46. data/spec/models/question_spec.rb +70 -0
  47. data/spec/spec_helper.rb +30 -0
  48. data/spec/support/capybara.rb +17 -0
  49. data/spec/support/database_cleaner.rb +18 -0
  50. data/spec/support/factory_girl.rb +7 -0
  51. data/spec/support/i18n.rb +13 -0
  52. data/spec/support/spree.rb +10 -0
  53. data/spec/translations/locale_spec.rb +15 -0
  54. data/spree_faq.gemspec +46 -0
  55. data/vendor/assets/javascripts/jquery.scrollTo-min.js +11 -0
  56. metadata +381 -0
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Admin::QuestionCategoriesController do
4
+ stub_authorization!
5
+
6
+ let!(:user) { create(:user) }
7
+ let!(:question_category) { create(:question_category) }
8
+ let!(:question) { create(:question, question_category: question_category) }
9
+ let (:attributes) { attributes_for(:question_category) }
10
+
11
+ before { controller.stub spree_current_user: user }
12
+
13
+ context 'controller instance' do
14
+ it 'use Admin::QuestionCategoriesController' do
15
+ expect(controller).to be_an_instance_of Spree::Admin::QuestionCategoriesController
16
+ end
17
+ end
18
+
19
+ context '#index' do
20
+ specify do
21
+ spree_get :index
22
+ expect(response).to render_template :index
23
+ end
24
+ end
25
+
26
+ context '#new' do
27
+ before { spree_get :new }
28
+
29
+ it { expect(assigns(:question_category)).to be_a_new Spree::QuestionCategory }
30
+ it { expect(response).to render_template :new }
31
+ end
32
+
33
+ context '#edit' do
34
+ before { spree_get :edit, id: question_category }
35
+
36
+ it { expect(assigns(:question_category)).to eq question_category }
37
+ it { expect(response).to render_template :edit }
38
+ end
39
+
40
+ context '#create' do
41
+ context 'with valid params' do
42
+ it 'creates a new Spree::QuestionCategory' do
43
+ expect {
44
+ spree_post :create, question_category: attributes
45
+ }.to change(Spree::QuestionCategory, :count).by(1)
46
+ end
47
+
48
+ it 'assigns a newly created question_category as @question_category' do
49
+ spree_post :create, question_category: attributes
50
+ expect(assigns(:question_category)).to be_a Spree::QuestionCategory
51
+ expect(assigns(:question_category)).to be_persisted
52
+ end
53
+ end
54
+ end
55
+
56
+ context '#destroy' do
57
+ it 'destroys the requested question_category' do
58
+ expect {
59
+ spree_delete :destroy, id: question_category
60
+ }.to change(Spree::QuestionCategory, :count).by(-1)
61
+ end
62
+
63
+ it 'requires the :id parameter' do
64
+ expect { spree_delete :destroy }.to raise_error
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::FaqsController do
4
+
5
+ let!(:question_category) { create(:question_category) }
6
+ let!(:question) { create(:question, question_category: question_category) }
7
+
8
+ before { controller.stub spree_current_user: nil }
9
+
10
+ context '#index' do
11
+ specify do
12
+ categories = [
13
+ question_category,
14
+ create(:question_category),
15
+ create(:question_category)
16
+ ]
17
+
18
+ spree_get :index
19
+ expect(assigns(:categories)).to eq categories
20
+ expect(response).to be_success
21
+ end
22
+ end
23
+
24
+ context '#default_title' do
25
+ it 'return default title' do
26
+ expect(subject.default_title).to eq Spree.t(:frequently_asked_questions, scope: :spree_faq)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :question_category, class: Spree::QuestionCategory do
3
+ sequence(:name) { |n| "category#{n}" }
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :question, class: Spree::Question do
3
+ question_category
4
+ sequence(:question) { |n| "question#{n}" }
5
+ answer { generate(:random_description) }
6
+ end
7
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Admin FAQ', :js do
4
+ stub_authorization!
5
+
6
+ given!(:admin_user) { create(:admin_user) }
7
+
8
+ background do
9
+ visit spree.admin_path
10
+ click_link 'Configuration'
11
+ end
12
+
13
+ scenario 'have faq tab in configuration sidebar' do
14
+ expect(page).to have_text 'FAQ'
15
+ end
16
+
17
+ context 'create new category' do
18
+
19
+ background do
20
+ click_link 'FAQ'
21
+ click_link 'New Category'
22
+ end
23
+
24
+ scenario 'save with valid name' do
25
+ fill_in 'Name', with: 'Shopping'
26
+ click_button 'Create'
27
+ within_table('listing_faq') do
28
+ expect(page).to have_text 'Shopping'
29
+ end
30
+ end
31
+
32
+ scenario 'error when empty name' do
33
+ click_button 'Create'
34
+ expect(page).to have_text 'Name can\'t be blank'
35
+ end
36
+ end
37
+
38
+ context 'modify' do
39
+
40
+ given!(:question_category) { create(:question_category, name: 'Shopping') }
41
+ given!(:question) do
42
+ create(:question,
43
+ question_category: question_category,
44
+ question: 'Do you sell stuff?',
45
+ answer: 'Think so..')
46
+ end
47
+
48
+ background do
49
+ click_link 'FAQ'
50
+ end
51
+
52
+ scenario 'update category' do
53
+ within_table('listing_faq') do
54
+ expect(page).to have_text 'Shopping'
55
+ click_icon :edit
56
+ end
57
+ expect(page).to have_text 'Editing Category Questions'
58
+
59
+ fill_in 'Category Name', with: 'Selling'
60
+ click_button 'Update'
61
+
62
+ within_table 'listing_faq' do
63
+ expect(page).to have_text 'Selling'
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'FAQ', :js do
4
+
5
+ given!(:user) { create(:user) }
6
+ given!(:question_category) { create(:question_category, name: 'Shopping') }
7
+ given!(:question) do
8
+ create(:question,
9
+ question_category: question_category,
10
+ question: 'Do you sell stuff?',
11
+ answer: 'Think so..')
12
+ end
13
+
14
+ background do
15
+ visit spree.faq_path
16
+ end
17
+
18
+ scenario 'have all elements' do
19
+ expect(page).to have_text Spree.t(:frequently_asked_questions, scope: :spree_faq)
20
+ expect(page).to have_text 'Shopping'
21
+ expect(page).to have_text 'Do you sell stuff?'
22
+ end
23
+
24
+ context 'when click on question' do
25
+ scenario 'show answer' do
26
+ click_link 'Do you sell stuff?'
27
+ expect(page).to have_text 'Think so..'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::QuestionCategory do
4
+
5
+ context 'instance attributes' do
6
+ it 'create a new instance given valid attributes' do
7
+ described_class.create!(name: 'Question 1')
8
+ end
9
+ end
10
+
11
+ context 'factory' do
12
+ it 'is valid' do
13
+ expect(build(:question_category)).to be_valid
14
+ end
15
+ end
16
+
17
+ context 'relation' do
18
+ it { should have_many(:questions) }
19
+
20
+ it 'have questions' do
21
+ expect(subject.questions).not_to be_nil
22
+ end
23
+ end
24
+
25
+ context 'validation' do
26
+ it { should validate_presence_of(:name) }
27
+ it { should validate_uniqueness_of(:name) }
28
+ it { should accept_nested_attributes_for(:questions) }
29
+ end
30
+
31
+ context 'mass assignment' do
32
+ %w(name questions_attributes question answer).each do |column|
33
+ it { should allow_mass_assignment_of(column.to_sym) }
34
+ end
35
+ end
36
+
37
+ context 'acts as list' do
38
+
39
+ subject { create(:question_category) }
40
+
41
+ before do
42
+ 2.times { create(:question_category) }
43
+ end
44
+
45
+ it 'can have its position changed' do
46
+ subject.move_to_bottom
47
+ expect(subject.position).to eq(3)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Question do
4
+
5
+ let!(:question_category) { create(:question_category) }
6
+ let(:question) { create(:question, question_category_id: question_category.id) }
7
+
8
+ subject { question }
9
+
10
+ context 'factory' do
11
+ it 'is valid' do
12
+ expect(build(:question)).to be_valid
13
+ end
14
+ end
15
+
16
+ context 'instance attributes' do
17
+ it 'create a new instance given valid attributes' do
18
+ described_class.create!(question: 'Question 1',
19
+ answer: 'Answer 1',
20
+ question_category: create(:question_category))
21
+ end
22
+ end
23
+
24
+ context 'relation' do
25
+ it { should belong_to(:question_category) }
26
+
27
+ it 'belong to a category' do
28
+ expect(subject.question_category).not_to be_nil
29
+ end
30
+ end
31
+
32
+ context 'validation' do
33
+ it { should validate_presence_of(:question_category_id) }
34
+ it { should validate_presence_of(:question) }
35
+ it { should validate_presence_of(:answer) }
36
+
37
+ it 'require a category' do
38
+ invalid_question = build(:question, question_category: nil)
39
+ expect(invalid_question).to have(1).error_on(:question_category_id)
40
+ end
41
+
42
+ it 'require a question' do
43
+ invalid_question = build(:question, question: nil)
44
+ expect(invalid_question).to have(1).error_on(:question)
45
+ end
46
+
47
+ it 'require a answer' do
48
+ invalid_question = build(:question, answer: nil)
49
+ expect(invalid_question).to have(1).error_on(:answer)
50
+ end
51
+ end
52
+
53
+ context 'mass assignment' do
54
+ %w(question answer question_category_id question_category).each do |column|
55
+ it { should allow_mass_assignment_of(column.to_sym) }
56
+ end
57
+ end
58
+
59
+ context 'acts as list' do
60
+
61
+ before do
62
+ 2.times { create(:question) }
63
+ end
64
+
65
+ it 'can have its position changed' do
66
+ subject.move_to_bottom
67
+ expect(subject.position).to eq(3)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,30 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
4
+ SimpleCov::Formatter::HTMLFormatter,
5
+ Coveralls::SimpleCov::Formatter
6
+ ]
7
+ SimpleCov.start do
8
+ add_filter 'spec'
9
+ add_filter 'lib/spree_faq/engine'
10
+ add_group 'Controllers', 'app/controllers'
11
+ add_group 'Overrides', 'app/overrides'
12
+ add_group 'Models', 'app/models'
13
+ add_group 'Libraries', 'lib'
14
+ end
15
+
16
+ ENV['RAILS_ENV'] = 'test'
17
+
18
+ require File.expand_path('../dummy/config/environment.rb', __FILE__)
19
+
20
+ require 'rspec/rails'
21
+ require 'shoulda-matchers'
22
+ require 'ffaker'
23
+
24
+ RSpec.configure do |config|
25
+ config.mock_with :rspec
26
+ config.use_transactional_fixtures = false
27
+ config.treat_symbols_as_metadata_keys_with_true_values = true
28
+ end
29
+
30
+ Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f }
@@ -0,0 +1,17 @@
1
+ require 'capybara/rspec'
2
+ require 'capybara/rails'
3
+ require 'capybara/poltergeist'
4
+
5
+ module CapybaraHelpers; end
6
+
7
+ RSpec.configure do |config|
8
+ config.include CapybaraHelpers, type: :feature
9
+
10
+ Capybara.javascript_driver = :poltergeist
11
+
12
+ config.before(:each, :js) do
13
+ if Capybara.javascript_driver == :selenium
14
+ page.driver.browser.manage.window.maximize
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'database_cleaner'
2
+
3
+ RSpec.configure do |config|
4
+
5
+ config.before :suite do
6
+ DatabaseCleaner.strategy = :transaction
7
+ DatabaseCleaner.clean_with :truncation
8
+ end
9
+
10
+ config.before do
11
+ DatabaseCleaner.strategy = example.metadata[:js] ? :truncation : :transaction
12
+ DatabaseCleaner.start
13
+ end
14
+
15
+ config.after do
16
+ DatabaseCleaner.clean
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'factory_girl'
2
+
3
+ FactoryGirl.find_definitions
4
+
5
+ RSpec.configure do |config|
6
+ config.include FactoryGirl::Syntax::Methods
7
+ end
@@ -0,0 +1,13 @@
1
+ require 'rspec'
2
+ require 'i18n-spec'
3
+
4
+ RSpec.configure do |config|
5
+
6
+ config.after(type: :feature) do
7
+ missing_translations = page.body.scan(/translation missing: #{I18n.locale}\.(.*?)[\s<\"&]/)
8
+ if missing_translations.any?
9
+ puts "\e[1m\e[35mFound missing translations: #{missing_translations.inspect}\e[0m"
10
+ puts "\e[1m\e[35mIn spec: #{example.location}\e[0m"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ require 'spree/testing_support/factories'
2
+ require 'spree/testing_support/controller_requests'
3
+ require 'spree/testing_support/authorization_helpers'
4
+ require 'spree/testing_support/url_helpers'
5
+ require 'spree/testing_support/capybara_ext'
6
+
7
+ RSpec.configure do |config|
8
+ config.include Spree::TestingSupport::ControllerRequests
9
+ config.include Spree::TestingSupport::UrlHelpers
10
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'locale' do
4
+ Dir.glob('config/locales/*.yml') do |locale_file|
5
+ context locale_file do
6
+ it { should be_parseable }
7
+ it { should have_valid_pluralization_keys }
8
+ it { should_not have_missing_pluralization_keys }
9
+ it { should have_one_top_level_namespace }
10
+ it { should_not have_legacy_interpolations }
11
+ it { should have_a_valid_locale }
12
+ it { should be_a_complete_translation_of 'config/locales/en.yml' }
13
+ end
14
+ end
15
+ end
data/spree_faq.gemspec ADDED
@@ -0,0 +1,46 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'spree_faq/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.platform = Gem::Platform::RUBY
8
+ s.name = 'spree-faq'
9
+ s.version = SpreeFaq.version
10
+ s.summary = %q{Adds an easy FAQ page for Spree Commerce}
11
+ s.description = %q{With this gem you get an faq page and the management tools to make it very easy to update your faq and reduce the demand on your sites customer service}
12
+ s.required_ruby_version = '>= 1.9.3'
13
+
14
+ s.authors = ['Josh Nussbaum', 'Tobias Bohwalli']
15
+ s.email = 'hi@futhr.io'
16
+ s.homepage = 'https://github.com/futhr/spree-faq'
17
+ s.license = %q{BSD-3}
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- spec/*`.split("\n")
21
+ s.require_path = 'lib'
22
+ s.requirements << 'none'
23
+
24
+ s.has_rdoc = false
25
+
26
+ s.add_runtime_dependency 'spree_core', '~> 2.0.0'
27
+
28
+ s.add_development_dependency 'rspec-rails', '~> 2.14'
29
+ s.add_development_dependency 'capybara', '~> 2.2.1'
30
+ s.add_development_dependency 'selenium-webdriver', '>= 2.40.0'
31
+ s.add_development_dependency 'poltergeist', '~> 1.5.0'
32
+ s.add_development_dependency 'factory_girl', '~> 4.4'
33
+ s.add_development_dependency 'shoulda-matchers', '~> 2.5'
34
+ s.add_development_dependency 'sqlite3', '~> 1.3.8'
35
+ s.add_development_dependency 'simplecov', '~> 0.7.1'
36
+ s.add_development_dependency 'database_cleaner', '~> 1.2.0'
37
+ s.add_development_dependency 'i18n-spec', '~> 0.4.1'
38
+ s.add_development_dependency 'coffee-rails', '~> 3.2.2'
39
+ s.add_development_dependency 'sass-rails', '~> 3.2.6'
40
+ s.add_development_dependency 'ffaker', '>= 1.24.0'
41
+ s.add_development_dependency 'guard-rspec', '>= 4.2.0'
42
+ s.add_development_dependency 'launchy', '>= 2.4.0'
43
+ s.add_development_dependency 'pry-rails', '>= 0.3.0'
44
+ s.add_development_dependency 'coveralls', '>= 0.7.0'
45
+ s.add_development_dependency 'localeapp', '>= 0.7.2'
46
+ end
@@ -0,0 +1,11 @@
1
+ /**
2
+ * jQuery.ScrollTo - Easy element scrolling using jQuery.
3
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
4
+ * Dual licensed under MIT and GPL.
5
+ * Date: 5/25/2009
6
+ * @author Ariel Flesler
7
+ * @version 1.4.2
8
+ *
9
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
10
+ */
11
+ ;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);