decidim-dev 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +24 -0
  3. data/Rakefile +2 -0
  4. data/app/views/decidim/dummy_resource/_linked_dummys.html.erb +5 -0
  5. data/config/i18n-tasks.yml +4 -0
  6. data/config/locales/ca.yml +5 -0
  7. data/config/locales/en.yml +5 -0
  8. data/config/locales/es.yml +5 -0
  9. data/config/locales/eu.yml +5 -0
  10. data/config/locales/fi.yml +5 -0
  11. data/lib/decidim/dev.rb +22 -0
  12. data/lib/decidim/dev/assets/Exampledocument.docx +0 -0
  13. data/lib/decidim/dev/assets/Exampledocument.odt +0 -0
  14. data/lib/decidim/dev/assets/Exampledocument.pdf +0 -0
  15. data/lib/decidim/dev/assets/avatar.jpg +0 -0
  16. data/lib/decidim/dev/assets/city.jpeg +0 -0
  17. data/lib/decidim/dev/assets/city2.jpeg +0 -0
  18. data/lib/decidim/dev/assets/city3.jpeg +0 -0
  19. data/lib/decidim/dev/assets/icon.png +0 -0
  20. data/lib/decidim/dev/assets/malicious.jpg +0 -0
  21. data/lib/decidim/dev/common_rake.rb +28 -0
  22. data/lib/decidim/dev/dummy_authorization_handler.rb +26 -0
  23. data/lib/decidim/dev/test/authorization_shared_examples.rb +23 -0
  24. data/lib/decidim/dev/test/base_spec_helper.rb +48 -0
  25. data/lib/decidim/dev/test/i18n_spec.rb +34 -0
  26. data/lib/decidim/dev/test/rspec_support/action_mailer.rb +72 -0
  27. data/lib/decidim/dev/test/rspec_support/active_job.rb +11 -0
  28. data/lib/decidim/dev/test/rspec_support/authenticated_controller_context.rb +9 -0
  29. data/lib/decidim/dev/test/rspec_support/authorization_handlers.rb +7 -0
  30. data/lib/decidim/dev/test/rspec_support/capybara.rb +73 -0
  31. data/lib/decidim/dev/test/rspec_support/database_cleaner.rb +13 -0
  32. data/lib/decidim/dev/test/rspec_support/engine_routes.rb +34 -0
  33. data/lib/decidim/dev/test/rspec_support/factory_girl.rb +4 -0
  34. data/lib/decidim/dev/test/rspec_support/feature.rb +91 -0
  35. data/lib/decidim/dev/test/rspec_support/feature_context.rb +44 -0
  36. data/lib/decidim/dev/test/rspec_support/geocoder.rb +11 -0
  37. data/lib/decidim/dev/test/rspec_support/helpers.rb +46 -0
  38. data/lib/decidim/dev/test/rspec_support/html_matchers.rb +6 -0
  39. data/lib/decidim/dev/test/rspec_support/i18n.rb +15 -0
  40. data/lib/decidim/dev/test/rspec_support/phantomjs_polyfills/bind-polyfill.js +18 -0
  41. data/lib/decidim/dev/test/rspec_support/phantomjs_polyfills/object-assign-polyfill.js +24 -0
  42. data/lib/decidim/dev/test/rspec_support/phantomjs_polyfills/promise.js +233 -0
  43. data/lib/decidim/dev/test/rspec_support/translation_helpers.rb +75 -0
  44. data/lib/decidim/dev/test/rspec_support/warden.rb +9 -0
  45. data/lib/decidim/dev/test/rspec_support/webmock.rb +2 -0
  46. data/lib/decidim/dev/test/rspec_support/wisper.rb +6 -0
  47. data/lib/decidim/dev/test/spec_helper.rb +37 -0
  48. data/lib/generators/decidim/dummy_generator.rb +80 -0
  49. data/lib/generators/decidim/templates/autoprefixer.yml +8 -0
  50. data/lib/generators/decidim/templates/autoprefixer_initializer.rb +16 -0
  51. data/lib/generators/decidim/templates/decidim_dev.rb +2 -0
  52. metadata +406 -0
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ RSpec.configure do |config|
3
+ config.before(:suite) do
4
+ DatabaseCleaner.strategy = :truncation
5
+ DatabaseCleaner.clean_with :truncation
6
+ end
7
+
8
+ config.around(:each) do |example|
9
+ DatabaseCleaner.cleaning do
10
+ example.run
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # This is a quick hack so all controller specs have their engine's routes
4
+ # included as well as our Devise mapping.
5
+ module ControllerRequests
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ begin
10
+ engine = (ENV["ENGINE_NAME"].to_s.split("-").map(&:capitalize).join("::") + "::Engine").constantize
11
+
12
+ load_routes engine if engine.respond_to?(:routes)
13
+ rescue NameError => _exception
14
+ puts "Failed to automatically inject routes for engine #{ENV["ENGINE_NAME"]}"
15
+ end
16
+ end
17
+
18
+ class_methods do
19
+ def load_routes(klass)
20
+ routes do
21
+ klass.routes
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ RSpec.configure do |config|
29
+ config.include Decidim::ControllerRequests, type: :controller
30
+
31
+ config.before :each, type: :controller do
32
+ @request.env["devise.mapping"] = Devise.mappings[:user]
33
+ end
34
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ RSpec.configure do |config|
3
+ config.include FactoryGirl::Syntax::Methods
4
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/feature_validator"
4
+ require "decidim/comments"
5
+
6
+ module Decidim
7
+ # Dummy engine to be able to test components.
8
+ class DummyEngine < Rails::Engine
9
+ engine_name "dummy"
10
+
11
+ routes do
12
+ root to: proc { [200, {}, ["DUMMY ENGINE"]] }
13
+ resources :dummy_resources, controller: "decidim/dummy_resources"
14
+ end
15
+ end
16
+
17
+ class DummyResource < ActiveRecord::Base
18
+ include HasFeature
19
+ include Resourceable
20
+ include Reportable
21
+ include Authorable
22
+ include Decidim::Comments::Commentable
23
+
24
+ feature_manifest_name "dummy"
25
+
26
+ def reported_content
27
+ title
28
+ end
29
+ end
30
+
31
+ class DummyResourcesController < ActionController::Base
32
+ helper Decidim::Comments::CommentsHelper
33
+ skip_authorization_check
34
+
35
+ def show
36
+ @commentable = DummyResource.find(params[:id])
37
+ render inline: %{
38
+ <%= display_flash_messages %>
39
+ <div class="reveal" id="loginModal" data-reveal></div>
40
+ <%= javascript_include_tag 'application' %>
41
+ <%= inline_comments_for(@commentable) %>
42
+ }
43
+ end
44
+ end
45
+ end
46
+
47
+ Decidim.register_feature(:dummy) do |feature|
48
+ feature.engine = Decidim::DummyEngine
49
+
50
+ feature.actions = %w(foo bar)
51
+
52
+ feature.settings(:global) do |settings|
53
+ settings.attribute :comments_enabled, type: :boolean, default: true
54
+ settings.attribute :dummy_global_attribute_1, type: :boolean
55
+ settings.attribute :dummy_global_attribute_2, type: :boolean
56
+ end
57
+
58
+ feature.settings(:step) do |settings|
59
+ settings.attribute :comments_blocked, type: :boolean, default: false
60
+ settings.attribute :dummy_step_attribute_1, type: :boolean
61
+ settings.attribute :dummy_step_attribute_2, type: :boolean
62
+ end
63
+
64
+ feature.register_resource do |resource|
65
+ resource.name = :dummy
66
+ resource.model_class_name = "Decidim::DummyResource"
67
+ resource.template = "decidim/dummy_resource/linked_dummys"
68
+ end
69
+ end
70
+
71
+ RSpec.configure do |config|
72
+ config.before(:suite) do
73
+ unless ActiveRecord::Base.connection.data_source_exists?("decidim_dummy_resources")
74
+ ActiveRecord::Migration.create_table :decidim_dummy_resources do |t|
75
+ t.string :title
76
+ t.text :address
77
+ t.float :latitude
78
+ t.float :longitude
79
+
80
+ t.references :decidim_feature, index: true
81
+ t.references :decidim_author, index: true
82
+
83
+ t.timestamps
84
+ end
85
+ end
86
+ end
87
+
88
+ config.before(:each) do
89
+ Decidim.find_feature_manifest(:dummy).reset_hooks!
90
+ end
91
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ RSpec.shared_context "feature" do
3
+ let!(:manifest_name) { raise NotImplementedError }
4
+ let(:manifest) { Decidim.find_feature_manifest(manifest_name) }
5
+
6
+ let!(:organization) { create(:organization) }
7
+
8
+ let(:participatory_process) do
9
+ create(:participatory_process, :with_steps, organization: organization)
10
+ end
11
+
12
+ let!(:feature) do
13
+ create(:feature,
14
+ manifest: manifest,
15
+ participatory_process: participatory_process)
16
+ end
17
+
18
+ before do
19
+ switch_to_host(organization.host)
20
+ end
21
+
22
+ def visit_feature
23
+ page.visit decidim.feature_path(participatory_process, feature)
24
+ end
25
+ end
26
+
27
+ RSpec.shared_context "feature admin" do
28
+ include_context "feature"
29
+ let(:user) { create(:user, :confirmed, organization: organization) }
30
+
31
+ before do
32
+ Decidim::Admin::ParticipatoryProcessUserRole.create!(
33
+ role: :admin,
34
+ user: user,
35
+ participatory_process: participatory_process
36
+ )
37
+
38
+ login_as user, scope: :user
39
+ end
40
+
41
+ def visit_feature_admin
42
+ visit decidim_admin.manage_feature_path(participatory_process, feature)
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ RSpec.configure do |config|
2
+ config.before(:each) do
3
+ # Set geocoder configuration in test mode
4
+ Decidim.geocoder = {
5
+ static_map_url: "http://www.example.org",
6
+ here_app_id: '1234',
7
+ here_app_code: '5678'
8
+ }
9
+ Geocoder.configure(lookup: :test)
10
+ end
11
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Helpers that get automatically included in feature specs.
4
+ module Decidim::FeatureTestHelpers
5
+ def within_user_menu
6
+ within ".topbar__user__logged" do
7
+ find("a", text: user.name).hover
8
+ yield
9
+ end
10
+ end
11
+
12
+ def within_language_menu
13
+ within ".topbar__dropmenu.language-choose" do
14
+ find("ul.dropdown.menu").hover
15
+ yield
16
+ end
17
+ end
18
+
19
+ def click_icon(name = nil)
20
+ classes = ["icon"]
21
+ classes << ["icon--#{name}"] if name
22
+ find(".#{classes.join(".")}").click
23
+ end
24
+
25
+ def stripped(text)
26
+ Nokogiri::HTML(text).text
27
+ end
28
+
29
+ def within_flash_messages
30
+ within ".flash.callout" do
31
+ yield
32
+ end
33
+ end
34
+
35
+ def expect_user_logged
36
+ expect(page).to have_css(".topbar__user__logged")
37
+ end
38
+ end
39
+
40
+ def stripped(text)
41
+ Nokogiri::HTML(text).text
42
+ end
43
+
44
+ RSpec.configure do |config|
45
+ config.include Decidim::FeatureTestHelpers, type: :feature
46
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ require "rspec-html-matchers"
3
+
4
+ RSpec.configure do |config|
5
+ config.include RSpecHtmlMatchers
6
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ RSpec.configure do |config|
3
+ config.before(:suite) do
4
+ I18n.config.enforce_available_locales = false
5
+ end
6
+
7
+ config.around(:each) do |example|
8
+ I18n.available_locales = %w{en ca es}
9
+ Decidim.available_locales = %w{en ca es}
10
+
11
+ previous_locale = I18n.locale
12
+ example.run
13
+ I18n.locale = previous_locale
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ if (typeof Function.prototype.bind != 'function') {
2
+ Function.prototype.bind = function bind(obj) {
3
+ var args = Array.prototype.slice.call(arguments, 1),
4
+ self = this,
5
+ nop = function() {
6
+ },
7
+ bound = function() {
8
+ return self.apply(
9
+ this instanceof nop ? this : (obj || {}), args.concat(
10
+ Array.prototype.slice.call(arguments)
11
+ )
12
+ );
13
+ };
14
+ nop.prototype = this.prototype || {};
15
+ bound.prototype = new nop();
16
+ return bound;
17
+ };
18
+ }
@@ -0,0 +1,24 @@
1
+ //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
2
+ if (typeof Object.assign != 'function') {
3
+ (function () {
4
+ Object.assign = function (target) {
5
+ 'use strict';
6
+ if (target === undefined || target === null) {
7
+ throw new TypeError('Cannot convert undefined or null to object');
8
+ }
9
+
10
+ var output = Object(target);
11
+ for (var index = 1; index < arguments.length; index++) {
12
+ var source = arguments[index];
13
+ if (source !== undefined && source !== null) {
14
+ for (var nextKey in source) {
15
+ if (source.hasOwnProperty(nextKey)) {
16
+ output[nextKey] = source[nextKey];
17
+ }
18
+ }
19
+ }
20
+ }
21
+ return output;
22
+ };
23
+ })();
24
+ }
@@ -0,0 +1,233 @@
1
+ (function (root) {
2
+
3
+ // Store setTimeout reference so promise-polyfill will be unaffected by
4
+ // other code modifying setTimeout (like sinon.useFakeTimers())
5
+ var setTimeoutFunc = setTimeout;
6
+
7
+ function noop() {}
8
+
9
+ // Polyfill for Function.prototype.bind
10
+ function bind(fn, thisArg) {
11
+ return function () {
12
+ fn.apply(thisArg, arguments);
13
+ };
14
+ }
15
+
16
+ function Promise(fn) {
17
+ if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
18
+ if (typeof fn !== 'function') throw new TypeError('not a function');
19
+ this._state = 0;
20
+ this._handled = false;
21
+ this._value = undefined;
22
+ this._deferreds = [];
23
+
24
+ doResolve(fn, this);
25
+ }
26
+
27
+ function handle(self, deferred) {
28
+ while (self._state === 3) {
29
+ self = self._value;
30
+ }
31
+ if (self._state === 0) {
32
+ self._deferreds.push(deferred);
33
+ return;
34
+ }
35
+ self._handled = true;
36
+ Promise._immediateFn(function () {
37
+ var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
38
+ if (cb === null) {
39
+ (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
40
+ return;
41
+ }
42
+ var ret;
43
+ try {
44
+ ret = cb(self._value);
45
+ } catch (e) {
46
+ reject(deferred.promise, e);
47
+ return;
48
+ }
49
+ resolve(deferred.promise, ret);
50
+ });
51
+ }
52
+
53
+ function resolve(self, newValue) {
54
+ try {
55
+ // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
56
+ if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
57
+ if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
58
+ var then = newValue.then;
59
+ if (newValue instanceof Promise) {
60
+ self._state = 3;
61
+ self._value = newValue;
62
+ finale(self);
63
+ return;
64
+ } else if (typeof then === 'function') {
65
+ doResolve(bind(then, newValue), self);
66
+ return;
67
+ }
68
+ }
69
+ self._state = 1;
70
+ self._value = newValue;
71
+ finale(self);
72
+ } catch (e) {
73
+ reject(self, e);
74
+ }
75
+ }
76
+
77
+ function reject(self, newValue) {
78
+ self._state = 2;
79
+ self._value = newValue;
80
+ finale(self);
81
+ }
82
+
83
+ function finale(self) {
84
+ if (self._state === 2 && self._deferreds.length === 0) {
85
+ Promise._immediateFn(function() {
86
+ if (!self._handled) {
87
+ Promise._unhandledRejectionFn(self._value);
88
+ }
89
+ });
90
+ }
91
+
92
+ for (var i = 0, len = self._deferreds.length; i < len; i++) {
93
+ handle(self, self._deferreds[i]);
94
+ }
95
+ self._deferreds = null;
96
+ }
97
+
98
+ function Handler(onFulfilled, onRejected, promise) {
99
+ this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
100
+ this.onRejected = typeof onRejected === 'function' ? onRejected : null;
101
+ this.promise = promise;
102
+ }
103
+
104
+ /**
105
+ * Take a potentially misbehaving resolver function and make sure
106
+ * onFulfilled and onRejected are only called once.
107
+ *
108
+ * Makes no guarantees about asynchrony.
109
+ */
110
+ function doResolve(fn, self) {
111
+ var done = false;
112
+ try {
113
+ fn(function (value) {
114
+ if (done) return;
115
+ done = true;
116
+ resolve(self, value);
117
+ }, function (reason) {
118
+ if (done) return;
119
+ done = true;
120
+ reject(self, reason);
121
+ });
122
+ } catch (ex) {
123
+ if (done) return;
124
+ done = true;
125
+ reject(self, ex);
126
+ }
127
+ }
128
+
129
+ Promise.prototype['catch'] = function (onRejected) {
130
+ return this.then(null, onRejected);
131
+ };
132
+
133
+ Promise.prototype.then = function (onFulfilled, onRejected) {
134
+ var prom = new (this.constructor)(noop);
135
+
136
+ handle(this, new Handler(onFulfilled, onRejected, prom));
137
+ return prom;
138
+ };
139
+
140
+ Promise.all = function (arr) {
141
+ var args = Array.prototype.slice.call(arr);
142
+
143
+ return new Promise(function (resolve, reject) {
144
+ if (args.length === 0) return resolve([]);
145
+ var remaining = args.length;
146
+
147
+ function res(i, val) {
148
+ try {
149
+ if (val && (typeof val === 'object' || typeof val === 'function')) {
150
+ var then = val.then;
151
+ if (typeof then === 'function') {
152
+ then.call(val, function (val) {
153
+ res(i, val);
154
+ }, reject);
155
+ return;
156
+ }
157
+ }
158
+ args[i] = val;
159
+ if (--remaining === 0) {
160
+ resolve(args);
161
+ }
162
+ } catch (ex) {
163
+ reject(ex);
164
+ }
165
+ }
166
+
167
+ for (var i = 0; i < args.length; i++) {
168
+ res(i, args[i]);
169
+ }
170
+ });
171
+ };
172
+
173
+ Promise.resolve = function (value) {
174
+ if (value && typeof value === 'object' && value.constructor === Promise) {
175
+ return value;
176
+ }
177
+
178
+ return new Promise(function (resolve) {
179
+ resolve(value);
180
+ });
181
+ };
182
+
183
+ Promise.reject = function (value) {
184
+ return new Promise(function (resolve, reject) {
185
+ reject(value);
186
+ });
187
+ };
188
+
189
+ Promise.race = function (values) {
190
+ return new Promise(function (resolve, reject) {
191
+ for (var i = 0, len = values.length; i < len; i++) {
192
+ values[i].then(resolve, reject);
193
+ }
194
+ });
195
+ };
196
+
197
+ // Use polyfill for setImmediate for performance gains
198
+ Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
199
+ function (fn) {
200
+ setTimeoutFunc(fn, 0);
201
+ };
202
+
203
+ Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
204
+ if (typeof console !== 'undefined' && console) {
205
+ console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
206
+ }
207
+ };
208
+
209
+ /**
210
+ * Set the immediate function to execute callbacks
211
+ * @param fn {function} Function to execute
212
+ * @deprecated
213
+ */
214
+ Promise._setImmediateFn = function _setImmediateFn(fn) {
215
+ Promise._immediateFn = fn;
216
+ };
217
+
218
+ /**
219
+ * Change the function to execute on unhandled rejection
220
+ * @param {function} fn Function to execute on unhandled rejection
221
+ * @deprecated
222
+ */
223
+ Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
224
+ Promise._unhandledRejectionFn = fn;
225
+ };
226
+
227
+ if (typeof module !== 'undefined' && module.exports) {
228
+ module.exports = Promise;
229
+ } else if (!root.Promise) {
230
+ root.Promise = Promise;
231
+ }
232
+
233
+ })(this);