hyper-mesh 0.4.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 (469) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +11 -0
  5. data/.travis.yml +4 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +5 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +396 -0
  10. data/Rakefile +6 -0
  11. data/app/controllers/reactive_record/application_controller.rb +4 -0
  12. data/app/controllers/reactive_record/reactive_record_controller.rb +49 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +7 -0
  15. data/codeship.database.yml +18 -0
  16. data/config/routes.rb +7 -0
  17. data/docs/action_cable_quickstart.md +151 -0
  18. data/docs/authorization-policies.md +449 -0
  19. data/docs/client_side_scoping.md +103 -0
  20. data/docs/pusher_quickstart.md +0 -0
  21. data/docs/simple_poller_quickstart.md +121 -0
  22. data/docs/todo-example.md +116 -0
  23. data/docs/words-example.md +65 -0
  24. data/examples/action-cable/.gitignore +21 -0
  25. data/examples/action-cable/Gemfile +58 -0
  26. data/examples/action-cable/Gemfile.lock +247 -0
  27. data/examples/action-cable/README.md +24 -0
  28. data/examples/action-cable/Rakefile +6 -0
  29. data/examples/action-cable/app/assets/config/manifest.js +3 -0
  30. data/examples/action-cable/app/assets/javascripts/application.js +18 -0
  31. data/examples/action-cable/app/assets/stylesheets/application.css +15 -0
  32. data/examples/action-cable/app/controllers/application_controller.rb +3 -0
  33. data/examples/action-cable/app/controllers/test_controller.rb +6 -0
  34. data/examples/action-cable/app/models/models.rb +2 -0
  35. data/examples/action-cable/app/models/public/application_record.rb +3 -0
  36. data/examples/action-cable/app/models/public/word.rb +2 -0
  37. data/examples/action-cable/app/policies/application_policy.rb +6 -0
  38. data/examples/action-cable/app/views/components.rb +17 -0
  39. data/examples/action-cable/app/views/components/app.rb +18 -0
  40. data/examples/action-cable/app/views/layouts/application.html.erb +14 -0
  41. data/examples/action-cable/app/views/layouts/mailer.html.erb +13 -0
  42. data/examples/action-cable/app/views/layouts/mailer.text.erb +1 -0
  43. data/examples/action-cable/bin/bundle +3 -0
  44. data/examples/action-cable/bin/rails +9 -0
  45. data/examples/action-cable/bin/rake +9 -0
  46. data/examples/action-cable/bin/setup +34 -0
  47. data/examples/action-cable/bin/spring +15 -0
  48. data/examples/action-cable/bin/update +29 -0
  49. data/examples/action-cable/config.ru +5 -0
  50. data/examples/action-cable/config/application.rb +30 -0
  51. data/examples/action-cable/config/boot.rb +3 -0
  52. data/examples/action-cable/config/cable.yml +9 -0
  53. data/examples/action-cable/config/database.yml +25 -0
  54. data/examples/action-cable/config/environment.rb +5 -0
  55. data/examples/action-cable/config/environments/development.rb +45 -0
  56. data/examples/action-cable/config/environments/production.rb +86 -0
  57. data/examples/action-cable/config/environments/test.rb +42 -0
  58. data/examples/action-cable/config/initializers/application_controller_renderer.rb +6 -0
  59. data/examples/action-cable/config/initializers/assets.rb +11 -0
  60. data/examples/action-cable/config/initializers/backtrace_silencers.rb +7 -0
  61. data/examples/action-cable/config/initializers/cookies_serializer.rb +5 -0
  62. data/examples/action-cable/config/initializers/filter_parameter_logging.rb +4 -0
  63. data/examples/action-cable/config/initializers/inflections.rb +16 -0
  64. data/examples/action-cable/config/initializers/mime_types.rb +4 -0
  65. data/examples/action-cable/config/initializers/new_framework_defaults.rb +24 -0
  66. data/examples/action-cable/config/initializers/session_store.rb +3 -0
  67. data/examples/action-cable/config/initializers/synchromesh.rb +5 -0
  68. data/examples/action-cable/config/initializers/wrap_parameters.rb +14 -0
  69. data/examples/action-cable/config/locales/en.yml +23 -0
  70. data/examples/action-cable/config/puma.rb +47 -0
  71. data/examples/action-cable/config/routes.rb +5 -0
  72. data/examples/action-cable/config/secrets.yml +22 -0
  73. data/examples/action-cable/config/spring.rb +6 -0
  74. data/examples/action-cable/db/migrate/20160921223808_create_words.rb +9 -0
  75. data/examples/action-cable/db/schema.rb +21 -0
  76. data/examples/action-cable/log/.keep +0 -0
  77. data/examples/action-cable/public/404.html +67 -0
  78. data/examples/action-cable/public/422.html +67 -0
  79. data/examples/action-cable/public/500.html +66 -0
  80. data/examples/action-cable/public/apple-touch-icon-precomposed.png +0 -0
  81. data/examples/action-cable/public/apple-touch-icon.png +0 -0
  82. data/examples/action-cable/public/favicon.ico +0 -0
  83. data/examples/action-cable/public/robots.txt +5 -0
  84. data/examples/action-cable/rails_cache_dir2/C91/480/synchromesh_active_connections +0 -0
  85. data/examples/action-cable/tmp/.keep +0 -0
  86. data/examples/action-cable/vendor/assets/javascripts/.keep +0 -0
  87. data/examples/action-cable/vendor/assets/stylesheets/.keep +0 -0
  88. data/examples/simple-poller/.gitignore +21 -0
  89. data/examples/simple-poller/Gemfile +64 -0
  90. data/examples/simple-poller/Gemfile.lock +272 -0
  91. data/examples/simple-poller/README.md +24 -0
  92. data/examples/simple-poller/Rakefile +6 -0
  93. data/examples/simple-poller/app/assets/config/manifest.js +3 -0
  94. data/examples/simple-poller/app/assets/images/.keep +0 -0
  95. data/examples/simple-poller/app/assets/javascripts/application.js +20 -0
  96. data/examples/simple-poller/app/assets/javascripts/channels/.keep +0 -0
  97. data/examples/simple-poller/app/assets/stylesheets/application.css +15 -0
  98. data/examples/simple-poller/app/channels/application_cable/channel.rb +4 -0
  99. data/examples/simple-poller/app/channels/application_cable/connection.rb +4 -0
  100. data/examples/simple-poller/app/controllers/application_controller.rb +3 -0
  101. data/examples/simple-poller/app/controllers/concerns/.keep +0 -0
  102. data/examples/simple-poller/app/controllers/test_controller.rb +6 -0
  103. data/examples/simple-poller/app/helpers/application_helper.rb +2 -0
  104. data/examples/simple-poller/app/jobs/application_job.rb +2 -0
  105. data/examples/simple-poller/app/mailers/application_mailer.rb +4 -0
  106. data/examples/simple-poller/app/models/concerns/.keep +0 -0
  107. data/examples/simple-poller/app/models/models.rb +2 -0
  108. data/examples/simple-poller/app/models/public/.keep +0 -0
  109. data/examples/simple-poller/app/models/public/application_record.rb +3 -0
  110. data/examples/simple-poller/app/models/public/word.rb +2 -0
  111. data/examples/simple-poller/app/policies/application_policy.rb +5 -0
  112. data/examples/simple-poller/app/views/components.rb +18 -0
  113. data/examples/simple-poller/app/views/components/.keep +0 -0
  114. data/examples/simple-poller/app/views/components/app.rb +40 -0
  115. data/examples/simple-poller/app/views/layouts/application.html.erb +14 -0
  116. data/examples/simple-poller/app/views/layouts/mailer.html.erb +13 -0
  117. data/examples/simple-poller/app/views/layouts/mailer.text.erb +1 -0
  118. data/examples/simple-poller/bin/bundle +3 -0
  119. data/examples/simple-poller/bin/rails +9 -0
  120. data/examples/simple-poller/bin/rake +9 -0
  121. data/examples/simple-poller/bin/setup +34 -0
  122. data/examples/simple-poller/bin/spring +16 -0
  123. data/examples/simple-poller/bin/update +29 -0
  124. data/examples/simple-poller/config.ru +5 -0
  125. data/examples/simple-poller/config/application.rb +20 -0
  126. data/examples/simple-poller/config/boot.rb +3 -0
  127. data/examples/simple-poller/config/cable.yml +9 -0
  128. data/examples/simple-poller/config/database.yml +25 -0
  129. data/examples/simple-poller/config/environment.rb +5 -0
  130. data/examples/simple-poller/config/environments/development.rb +44 -0
  131. data/examples/simple-poller/config/environments/production.rb +86 -0
  132. data/examples/simple-poller/config/environments/test.rb +42 -0
  133. data/examples/simple-poller/config/initializers/application_controller_renderer.rb +6 -0
  134. data/examples/simple-poller/config/initializers/assets.rb +11 -0
  135. data/examples/simple-poller/config/initializers/backtrace_silencers.rb +7 -0
  136. data/examples/simple-poller/config/initializers/cookies_serializer.rb +5 -0
  137. data/examples/simple-poller/config/initializers/filter_parameter_logging.rb +4 -0
  138. data/examples/simple-poller/config/initializers/inflections.rb +16 -0
  139. data/examples/simple-poller/config/initializers/mime_types.rb +4 -0
  140. data/examples/simple-poller/config/initializers/new_framework_defaults.rb +24 -0
  141. data/examples/simple-poller/config/initializers/session_store.rb +3 -0
  142. data/examples/simple-poller/config/initializers/synchromesh.rb +15 -0
  143. data/examples/simple-poller/config/initializers/wrap_parameters.rb +14 -0
  144. data/examples/simple-poller/config/locales/en.yml +23 -0
  145. data/examples/simple-poller/config/puma.rb +47 -0
  146. data/examples/simple-poller/config/routes.rb +5 -0
  147. data/examples/simple-poller/config/secrets.yml +22 -0
  148. data/examples/simple-poller/config/spring.rb +6 -0
  149. data/examples/simple-poller/db/migrate/20161013220135_create_words.rb +9 -0
  150. data/examples/simple-poller/db/schema.rb +21 -0
  151. data/examples/simple-poller/db/seeds.rb +7 -0
  152. data/examples/simple-poller/lib/assets/.keep +0 -0
  153. data/examples/simple-poller/lib/tasks/.keep +0 -0
  154. data/examples/simple-poller/log/.keep +0 -0
  155. data/examples/simple-poller/public/404.html +67 -0
  156. data/examples/simple-poller/public/422.html +67 -0
  157. data/examples/simple-poller/public/500.html +66 -0
  158. data/examples/simple-poller/public/apple-touch-icon-precomposed.png +0 -0
  159. data/examples/simple-poller/public/apple-touch-icon.png +0 -0
  160. data/examples/simple-poller/public/favicon.ico +0 -0
  161. data/examples/simple-poller/public/robots.txt +5 -0
  162. data/examples/simple-poller/test/controllers/.keep +0 -0
  163. data/examples/simple-poller/test/fixtures/.keep +0 -0
  164. data/examples/simple-poller/test/fixtures/files/.keep +0 -0
  165. data/examples/simple-poller/test/fixtures/words.yml +7 -0
  166. data/examples/simple-poller/test/helpers/.keep +0 -0
  167. data/examples/simple-poller/test/integration/.keep +0 -0
  168. data/examples/simple-poller/test/mailers/.keep +0 -0
  169. data/examples/simple-poller/test/models/.keep +0 -0
  170. data/examples/simple-poller/test/models/word_test.rb +7 -0
  171. data/examples/simple-poller/test/test_helper.rb +10 -0
  172. data/examples/simple-poller/tmp/.keep +0 -0
  173. data/examples/simple-poller/vendor/assets/javascripts/.keep +0 -0
  174. data/examples/simple-poller/vendor/assets/stylesheets/.keep +0 -0
  175. data/examples/words/.gitignore +21 -0
  176. data/examples/words/Gemfile +58 -0
  177. data/examples/words/Gemfile.lock +247 -0
  178. data/examples/words/README.md +24 -0
  179. data/examples/words/Rakefile +6 -0
  180. data/examples/words/app/assets/config/manifest.js +3 -0
  181. data/examples/words/app/assets/javascripts/application.js +18 -0
  182. data/examples/words/app/assets/stylesheets/application.css +15 -0
  183. data/examples/words/app/controllers/application_controller.rb +3 -0
  184. data/examples/words/app/controllers/test_controller.rb +6 -0
  185. data/examples/words/app/models/models.rb +2 -0
  186. data/examples/words/app/models/public/application_record.rb +3 -0
  187. data/examples/words/app/models/public/word.rb +10 -0
  188. data/examples/words/app/policies/application_policy.rb +6 -0
  189. data/examples/words/app/views/components.rb +16 -0
  190. data/examples/words/app/views/components/app.rb +31 -0
  191. data/examples/words/app/views/layouts/application.html.erb +14 -0
  192. data/examples/words/app/views/layouts/mailer.html.erb +13 -0
  193. data/examples/words/app/views/layouts/mailer.text.erb +1 -0
  194. data/examples/words/bin/bundle +3 -0
  195. data/examples/words/bin/rails +9 -0
  196. data/examples/words/bin/rake +9 -0
  197. data/examples/words/bin/setup +34 -0
  198. data/examples/words/bin/spring +15 -0
  199. data/examples/words/bin/update +29 -0
  200. data/examples/words/config.ru +5 -0
  201. data/examples/words/config/application.rb +30 -0
  202. data/examples/words/config/boot.rb +3 -0
  203. data/examples/words/config/cable.yml +9 -0
  204. data/examples/words/config/database.yml +25 -0
  205. data/examples/words/config/environment.rb +5 -0
  206. data/examples/words/config/environments/development.rb +45 -0
  207. data/examples/words/config/environments/production.rb +86 -0
  208. data/examples/words/config/environments/test.rb +42 -0
  209. data/examples/words/config/initializers/application_controller_renderer.rb +6 -0
  210. data/examples/words/config/initializers/assets.rb +11 -0
  211. data/examples/words/config/initializers/backtrace_silencers.rb +7 -0
  212. data/examples/words/config/initializers/cookies_serializer.rb +5 -0
  213. data/examples/words/config/initializers/filter_parameter_logging.rb +4 -0
  214. data/examples/words/config/initializers/inflections.rb +16 -0
  215. data/examples/words/config/initializers/mime_types.rb +4 -0
  216. data/examples/words/config/initializers/new_framework_defaults.rb +24 -0
  217. data/examples/words/config/initializers/session_store.rb +3 -0
  218. data/examples/words/config/initializers/synchromesh.rb +5 -0
  219. data/examples/words/config/initializers/wrap_parameters.rb +14 -0
  220. data/examples/words/config/locales/en.yml +23 -0
  221. data/examples/words/config/puma.rb +47 -0
  222. data/examples/words/config/routes.rb +5 -0
  223. data/examples/words/config/secrets.yml +22 -0
  224. data/examples/words/config/spring.rb +6 -0
  225. data/examples/words/db/migrate/20160921223808_create_words.rb +9 -0
  226. data/examples/words/db/schema.rb +28 -0
  227. data/examples/words/log/.keep +0 -0
  228. data/examples/words/public/404.html +67 -0
  229. data/examples/words/public/422.html +67 -0
  230. data/examples/words/public/500.html +66 -0
  231. data/examples/words/public/apple-touch-icon-precomposed.png +0 -0
  232. data/examples/words/public/apple-touch-icon.png +0 -0
  233. data/examples/words/public/favicon.ico +0 -0
  234. data/examples/words/public/robots.txt +5 -0
  235. data/examples/words/tmp/.keep +0 -0
  236. data/examples/words/vendor/assets/javascripts/.keep +0 -0
  237. data/examples/words/vendor/assets/stylesheets/.keep +0 -0
  238. data/hyper-mesh.gemspec +82 -0
  239. data/lib/active_record_base.rb +152 -0
  240. data/lib/enumerable/pluck.rb +6 -0
  241. data/lib/hyper-mesh.rb +62 -0
  242. data/lib/hypermesh/version.rb +3 -0
  243. data/lib/opal/equality_patches.rb +15 -0
  244. data/lib/opal/parse_patch.rb +14 -0
  245. data/lib/opal/set_patches.rb +8 -0
  246. data/lib/reactive_record/active_record/aggregations.rb +69 -0
  247. data/lib/reactive_record/active_record/associations.rb +111 -0
  248. data/lib/reactive_record/active_record/base.rb +9 -0
  249. data/lib/reactive_record/active_record/class_methods.rb +177 -0
  250. data/lib/reactive_record/active_record/error.rb +26 -0
  251. data/lib/reactive_record/active_record/instance_methods.rb +129 -0
  252. data/lib/reactive_record/active_record/public_columns_hash.rb +19 -0
  253. data/lib/reactive_record/active_record/reactive_record/base.rb +520 -0
  254. data/lib/reactive_record/active_record/reactive_record/collection.rb +517 -0
  255. data/lib/reactive_record/active_record/reactive_record/column_types.rb +67 -0
  256. data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +218 -0
  257. data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +532 -0
  258. data/lib/reactive_record/active_record/reactive_record/reactive_set_relationship_helpers.rb +189 -0
  259. data/lib/reactive_record/active_record/reactive_record/scoped_collection.rb +62 -0
  260. data/lib/reactive_record/active_record/reactive_record/unscoped_collection.rb +16 -0
  261. data/lib/reactive_record/active_record/reactive_record/while_loading.rb +299 -0
  262. data/lib/reactive_record/engine.rb +13 -0
  263. data/lib/reactive_record/interval.rb +190 -0
  264. data/lib/reactive_record/permissions.rb +102 -0
  265. data/lib/reactive_record/pry.rb +13 -0
  266. data/lib/reactive_record/reactive_scope.rb +18 -0
  267. data/lib/reactive_record/scope_description.rb +108 -0
  268. data/lib/reactive_record/serializers.rb +7 -0
  269. data/lib/reactive_record/server_data_cache.rb +347 -0
  270. data/lib/reactive_record/version.rb +3 -0
  271. data/lib/sources/hyper-mesh/pusher.js +98 -0
  272. data/lib/synchromesh/action_cable.rb +39 -0
  273. data/lib/synchromesh/client_drivers.rb +357 -0
  274. data/lib/synchromesh/configuration.rb +40 -0
  275. data/lib/synchromesh/connection.rb +144 -0
  276. data/lib/synchromesh/policy.rb +504 -0
  277. data/lib/synchromesh/reactive_record/permission_patches.rb +43 -0
  278. data/lib/synchromesh/synchromesh.rb +155 -0
  279. data/lib/synchromesh/synchromesh_controller.rb +154 -0
  280. data/logo.jpg +0 -0
  281. data/path_release_steps.md +0 -0
  282. data/reactive_record_test_app/Gemfile +15 -0
  283. data/reactive_record_test_app/Gemfile.lock +209 -0
  284. data/reactive_record_test_app/README.rdoc +261 -0
  285. data/reactive_record_test_app/Rakefile +7 -0
  286. data/reactive_record_test_app/app/assets/javascripts/application.rb +5 -0
  287. data/reactive_record_test_app/app/assets/javascripts/components/another_component.rb +24 -0
  288. data/reactive_record_test_app/app/assets/javascripts/components/empty_component.rb +6 -0
  289. data/reactive_record_test_app/app/assets/javascripts/components/todo_item_component.js.rb +16 -0
  290. data/reactive_record_test_app/app/assets/javascripts/components/todos_component.js.rb +42 -0
  291. data/reactive_record_test_app/app/assets/javascripts/components/todos_main_component.rb +49 -0
  292. data/reactive_record_test_app/app/assets/javascripts/react_js_test_only.js +21618 -0
  293. data/reactive_record_test_app/app/assets/javascripts/reactive_record_config.js +2 -0
  294. data/reactive_record_test_app/app/assets/javascripts/spec/reactive_record_xspec.js.rb +42 -0
  295. data/reactive_record_test_app/app/assets/stylesheets/application.css +13 -0
  296. data/reactive_record_test_app/app/controllers/application_controller.rb +8 -0
  297. data/reactive_record_test_app/app/controllers/home_controller.rb +7 -0
  298. data/reactive_record_test_app/app/controllers/test_controller.rb +7 -0
  299. data/reactive_record_test_app/app/helpers/application_helper.rb +2 -0
  300. data/reactive_record_test_app/app/mailers/.gitkeep +0 -0
  301. data/reactive_record_test_app/app/models/.gitkeep +0 -0
  302. data/reactive_record_test_app/app/policies/application_policy.rb +5 -0
  303. data/reactive_record_test_app/app/views/components.rb +4 -0
  304. data/reactive_record_test_app/app/views/components/test.rb +18 -0
  305. data/reactive_record_test_app/app/views/home/index.html.erb +1 -0
  306. data/reactive_record_test_app/app/views/layouts/application.html.erb +17 -0
  307. data/reactive_record_test_app/app/views/models.rb +1 -0
  308. data/reactive_record_test_app/app/views/models/address.rb +13 -0
  309. data/reactive_record_test_app/app/views/models/comment.rb +19 -0
  310. data/reactive_record_test_app/app/views/models/todo_item.rb +36 -0
  311. data/reactive_record_test_app/app/views/models/user.rb +78 -0
  312. data/reactive_record_test_app/config.ru +33 -0
  313. data/reactive_record_test_app/config/application.rb +73 -0
  314. data/reactive_record_test_app/config/boot.rb +10 -0
  315. data/reactive_record_test_app/config/database.yml +25 -0
  316. data/reactive_record_test_app/config/environment.rb +5 -0
  317. data/reactive_record_test_app/config/environments/development.rb +43 -0
  318. data/reactive_record_test_app/config/environments/production.rb +70 -0
  319. data/reactive_record_test_app/config/environments/test.rb +41 -0
  320. data/reactive_record_test_app/config/initializers/backtrace_silencers.rb +7 -0
  321. data/reactive_record_test_app/config/initializers/inflections.rb +15 -0
  322. data/reactive_record_test_app/config/initializers/mime_types.rb +5 -0
  323. data/reactive_record_test_app/config/initializers/secret_token.rb +7 -0
  324. data/reactive_record_test_app/config/initializers/session_store.rb +8 -0
  325. data/reactive_record_test_app/config/initializers/wrap_parameters.rb +14 -0
  326. data/reactive_record_test_app/config/locales/en.yml +5 -0
  327. data/reactive_record_test_app/config/routes.rb +7 -0
  328. data/reactive_record_test_app/db/migrate/20150617002932_create_todo_items.rb +11 -0
  329. data/reactive_record_test_app/db/migrate/20150617134028_create_users.rb +14 -0
  330. data/reactive_record_test_app/db/migrate/20150729195556_add_address_to_user.rb +20 -0
  331. data/reactive_record_test_app/db/migrate/20150826142045_create_comments.rb +10 -0
  332. data/reactive_record_test_app/db/migrate/20150828172008_add_single_comment_to_todo_item.rb +5 -0
  333. data/reactive_record_test_app/db/migrate/20150908184118_add_address_id_to_user.rb +5 -0
  334. data/reactive_record_test_app/db/migrate/20150917220236_add_second_address_to_user.rb +10 -0
  335. data/reactive_record_test_app/db/migrate/20151009000111_add_test_data_attributes_to_user.rb +6 -0
  336. data/reactive_record_test_app/db/migrate/20160129182544_add_test_enum_to_user.rb +5 -0
  337. data/reactive_record_test_app/db/schema.rb +63 -0
  338. data/reactive_record_test_app/db/seeds.rb +60 -0
  339. data/reactive_record_test_app/public/404.html +26 -0
  340. data/reactive_record_test_app/public/422.html +26 -0
  341. data/reactive_record_test_app/public/500.html +25 -0
  342. data/reactive_record_test_app/public/favicon.ico +0 -0
  343. data/reactive_record_test_app/script/rails +6 -0
  344. data/reactive_record_test_app/spec-opal/active-record/aggregations_spec.rb +41 -0
  345. data/reactive_record_test_app/spec-opal/active-record/associations_spec.rb +75 -0
  346. data/reactive_record_test_app/spec-opal/active-record/base_spec.rb +126 -0
  347. data/reactive_record_test_app/spec-opal/active-record/dummy_value_spec.rb +27 -0
  348. data/reactive_record_test_app/spec-opal/active-record/edge_cases_spec.rb +116 -0
  349. data/reactive_record_test_app/spec-opal/active-record/enum_spec.rb +43 -0
  350. data/reactive_record_test_app/spec-opal/active-record/instance_methods_spec.rb +53 -0
  351. data/reactive_record_test_app/spec-opal/active-record/non_ar_aggregations_spec.rb +74 -0
  352. data/reactive_record_test_app/spec-opal/active-record/permissions_spec.rb +170 -0
  353. data/reactive_record_test_app/spec-opal/active-record/prerendering_spec.rb +49 -0
  354. data/reactive_record_test_app/spec-opal/active-record/reactive_record_load_spec.rb +23 -0
  355. data/reactive_record_test_app/spec-opal/active-record/rendering_spec.rb +221 -0
  356. data/reactive_record_test_app/spec-opal/active-record/save_spec.rb +125 -0
  357. data/reactive_record_test_app/spec-opal/active-record/scope_spec.rb +85 -0
  358. data/reactive_record_test_app/spec-opal/active-record/update_aggregations_spec.rb +76 -0
  359. data/reactive_record_test_app/spec-opal/active-record/update_attributes_spec.rb +186 -0
  360. data/reactive_record_test_app/spec-opal/active-record/virtual_methods_spec.rb +71 -0
  361. data/reactive_record_test_app/spec-opal/index.html.erb +11 -0
  362. data/reactive_record_test_app/spec-opal/spec_helper.js.rb +268 -0
  363. data/reactive_record_test_app/spec-opal/vendor/es5-shim.min.js +6 -0
  364. data/reactive_record_test_app/spec_dont_run/README.md +26 -0
  365. data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzmany_to_many_spec_moved_to_main_suite.rb +30 -0
  366. data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzrevert_record_spec_moved.rb +78 -0
  367. data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzupdate_associations_spec_moved.rb +142 -0
  368. data/reactive_record_test_app/spec_dont_run/moved_to_main_spec_dir/zzzupdate_scopes_movedspec.rb +48 -0
  369. data/remote.md +115 -0
  370. data/spec/bin/firebug-2.0.13-fx.xpi +0 -0
  371. data/spec/component_helpers_xspec.rb +49 -0
  372. data/spec/factories/child_model.rb +5 -0
  373. data/spec/factories/comment.rb +5 -0
  374. data/spec/factories/test_models.rb +5 -0
  375. data/spec/factories/todo.rb +5 -0
  376. data/spec/factories/user.rb +5 -0
  377. data/spec/reactive_record/edge_cases_spec.rb +31 -0
  378. data/spec/reactive_record/factory.rb +62 -0
  379. data/spec/reactive_record/many_to_many_spec.rb +50 -0
  380. data/spec/reactive_record/play.rb +64 -0
  381. data/spec/reactive_record/pry_rescue_xspec.rb +48 -0
  382. data/spec/reactive_record/revert_spec.rb +112 -0
  383. data/spec/reactive_record/update_associations_spec.rb +189 -0
  384. data/spec/reactive_record/update_scopes_spec.rb +53 -0
  385. data/spec/spec_helper.rb +366 -0
  386. data/spec/support/component_helpers.rb +351 -0
  387. data/spec/synchromesh/column_types/column_type_spec.rb +302 -0
  388. data/spec/synchromesh/connection_spec.rb +144 -0
  389. data/spec/synchromesh/crud_access_regulation/broadcast_controls_access_spec.rb +105 -0
  390. data/spec/synchromesh/crud_access_regulation/model_policies_spec.rb +131 -0
  391. data/spec/synchromesh/examples/dictionary.rb +239 -0
  392. data/spec/synchromesh/examples/dictionary_with_client_scopes.rb +196 -0
  393. data/spec/synchromesh/examples/random_examples.rb +100 -0
  394. data/spec/synchromesh/examples/scoped_todos_spec.rb +167 -0
  395. data/spec/synchromesh/integration/authorization_spec.rb +111 -0
  396. data/spec/synchromesh/integration/default_scope_spec.rb +121 -0
  397. data/spec/synchromesh/integration/has_many_through_spec.rb +173 -0
  398. data/spec/synchromesh/integration/relationships_spec.rb +263 -0
  399. data/spec/synchromesh/integration/scope_spec.rb +553 -0
  400. data/spec/synchromesh/integration/synchromesh_spec.rb +80 -0
  401. data/spec/synchromesh/integration/test_components.rb +18 -0
  402. data/spec/synchromesh/integration/transports_spec.rb +308 -0
  403. data/spec/synchromesh/policies/auto_connect_spec.rb +60 -0
  404. data/spec/synchromesh/policies/auto_loader_spec.rb +34 -0
  405. data/spec/synchromesh/policies/policy_methods_spec.rb +85 -0
  406. data/spec/synchromesh/policies/regulate_all_broadcasts_spec.rb +315 -0
  407. data/spec/synchromesh/policies/regulate_broadcast_spec.rb +370 -0
  408. data/spec/synchromesh/policies/regulate_class_connection_spec.rb +50 -0
  409. data/spec/synchromesh/policies/regulate_instance_connection_spec.rb +66 -0
  410. data/spec/test_app/Gemfile +61 -0
  411. data/spec/test_app/Gemfile.lock +253 -0
  412. data/spec/test_app/Rakefile +6 -0
  413. data/spec/test_app/app/assets/javascripts/application.js +6 -0
  414. data/spec/test_app/app/assets/stylesheets/application.css +15 -0
  415. data/spec/test_app/app/controllers/application_controller.rb +13 -0
  416. data/spec/test_app/app/controllers/test_controller.rb +5 -0
  417. data/spec/test_app/app/models/_react_public_models.rb +2 -0
  418. data/spec/test_app/app/models/public/address.rb +13 -0
  419. data/spec/test_app/app/models/public/child_model.rb +3 -0
  420. data/spec/test_app/app/models/public/comment.rb +25 -0
  421. data/spec/test_app/app/models/public/test_model.rb +5 -0
  422. data/spec/test_app/app/models/public/todo.rb +6 -0
  423. data/spec/test_app/app/models/public/todo_item.rb +36 -0
  424. data/spec/test_app/app/models/public/user.rb +88 -0
  425. data/spec/test_app/app/policies/auto_loader_test_classa_policy.rb +3 -0
  426. data/spec/test_app/app/policies/auto_loader_test_classb_policy.rb +3 -0
  427. data/spec/test_app/app/policies/auto_loader_test_classc_policy.rb +3 -0
  428. data/spec/test_app/app/policies/auto_loader_test_classd_policy.rb +3 -0
  429. data/spec/test_app/app/views/components.rb +14 -0
  430. data/spec/test_app/app/views/components/show.rb +5 -0
  431. data/spec/test_app/app/views/layouts/application.html.erb +14 -0
  432. data/spec/test_app/bin/bundle +3 -0
  433. data/spec/test_app/bin/rails +4 -0
  434. data/spec/test_app/bin/rake +4 -0
  435. data/spec/test_app/bin/setup +29 -0
  436. data/spec/test_app/config.ru +4 -0
  437. data/spec/test_app/config/application.rb +42 -0
  438. data/spec/test_app/config/boot.rb +6 -0
  439. data/spec/test_app/config/cable.yml +10 -0
  440. data/spec/test_app/config/database.yml +47 -0
  441. data/spec/test_app/config/environment.rb +5 -0
  442. data/spec/test_app/config/environments/development.rb +41 -0
  443. data/spec/test_app/config/environments/production.rb +79 -0
  444. data/spec/test_app/config/environments/test.rb +42 -0
  445. data/spec/test_app/config/initializers/assets.rb +11 -0
  446. data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
  447. data/spec/test_app/config/initializers/cookies_serializer.rb +3 -0
  448. data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
  449. data/spec/test_app/config/initializers/inflections.rb +16 -0
  450. data/spec/test_app/config/initializers/mime_types.rb +4 -0
  451. data/spec/test_app/config/initializers/session_store.rb +3 -0
  452. data/spec/test_app/config/initializers/synchromesh.rb +11 -0
  453. data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
  454. data/spec/test_app/config/locales/en.yml +23 -0
  455. data/spec/test_app/config/routes.rb +61 -0
  456. data/spec/test_app/config/secrets.yml +22 -0
  457. data/spec/test_app/db/development.sqlite3 +0 -0
  458. data/spec/test_app/db/migrate/20160731182106_create_test_models.rb +75 -0
  459. data/spec/test_app/db/schema.rb +88 -0
  460. data/spec/test_app/db/seeds.rb +7 -0
  461. data/spec/test_app/lib/assets/.keep +0 -0
  462. data/spec/test_app/log/.keep +0 -0
  463. data/spec/test_app/public/404.html +67 -0
  464. data/spec/test_app/public/422.html +67 -0
  465. data/spec/test_app/public/500.html +66 -0
  466. data/spec/test_app/public/favicon.ico +0 -0
  467. data/spec/vendor/es5-shim.min.js +6 -0
  468. data/terminal.md +66 -0
  469. metadata +1175 -0
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'synchromesh/integration/test_components'
3
+ require 'reactive_record/factory'
4
+ require 'rspec-steps'
5
+
6
+ RSpec::Steps.steps "updating scopes", js: true do
7
+
8
+ before(:all) do
9
+ seed_database
10
+ end
11
+
12
+ before(:step) do
13
+ # spec_helper resets the policy system after each test so we have to setup
14
+ # before each test
15
+ stub_const 'TestApplication', Class.new
16
+ stub_const 'TestApplicationPolicy', Class.new
17
+ TestApplicationPolicy.class_eval do
18
+ regulate_all_broadcasts { |policy| policy.send_all }
19
+ allow_change(to: :all, on: [:create, :update, :destroy]) { true }
20
+ end
21
+ size_window(:small, :portrait)
22
+ end
23
+
24
+ it "will update .all and rerender after saving a record" do
25
+ mount "TestComponent" do
26
+ class TestComponent < React::Component::Base
27
+ def render
28
+ #div do
29
+ "TodoItem.count = #{TodoItem.all.count}".span
30
+ #ul { TodoItem.each { |todo| li { todo.id.to_s } }}
31
+ #end
32
+ end
33
+ end
34
+ end
35
+ starting_count = TodoItem.count
36
+ expect(page).to have_content("TodoItem.count = #{starting_count}")
37
+ evaluate_ruby { TodoItem.new(title: "play it again sam").save }
38
+ expect(page).to have_content("TodoItem.count = #{starting_count+1}")
39
+ end
40
+
41
+ it "destroying records causes a rerender" do
42
+ count = TodoItem.count
43
+ while count > 0
44
+ expect(page).to have_content("TodoItem.count = #{count}")
45
+ evaluate_ruby do
46
+ ReactiveRecord.load { TodoItem.last.itself }.then { |todo| todo.destroy }
47
+ end
48
+ count -= 1
49
+ end
50
+ expect(page).to have_content("TodoItem.count = 0")
51
+ end
52
+
53
+ end
@@ -0,0 +1,366 @@
1
+ # spec/spec_helper.rb
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+
4
+ require 'opal'
5
+
6
+ def opal?
7
+ RUBY_ENGINE == 'opal'
8
+ end
9
+
10
+ def ruby?
11
+ !opal?
12
+ end
13
+
14
+ if RUBY_ENGINE == 'opal'
15
+ require 'hyper-react'
16
+ require File.expand_path('../support/react/spec_helpers', __FILE__)
17
+
18
+ module Opal
19
+ module RSpec
20
+ module AsyncHelpers
21
+ module ClassMethods
22
+ def rendering(title, &block)
23
+ klass = Class.new do
24
+ include React::Component
25
+
26
+ def self.block
27
+ @block
28
+ end
29
+
30
+ def self.name
31
+ "dummy class"
32
+ end
33
+
34
+ def render
35
+ instance_eval &self.class.block
36
+ end
37
+
38
+ def self.should_generate(opts={}, &block)
39
+ sself = self
40
+ @self.async(@title, opts) do
41
+ expect_component_to_eventually(sself, &block)
42
+ end
43
+ end
44
+
45
+ def self.should_immediately_generate(opts={}, &block)
46
+ sself = self
47
+ @self.it(@title, opts) do
48
+ element = build_element sself, {}
49
+ context = block.arity > 0 ? self : element
50
+ expect((element and context.instance_exec(element, &block))).to be(true)
51
+ end
52
+ end
53
+
54
+ end
55
+ klass.instance_variable_set("@block", block)
56
+ klass.instance_variable_set("@self", self)
57
+ klass.instance_variable_set("@title", "it can render #{title}")
58
+ klass
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ RSpec.configure do |config|
67
+ config.include React::SpecHelpers
68
+ config.filter_run_including :opal => true
69
+ end
70
+ end
71
+
72
+ if RUBY_ENGINE != 'opal'
73
+ require 'pry'
74
+ begin
75
+ require File.expand_path('../test_app/config/environment', __FILE__)
76
+ rescue LoadError
77
+ puts 'Could not load test application. Please ensure you have run `bundle exec rake test_app`'
78
+ end
79
+ require 'rspec/rails'
80
+ require 'timecop'
81
+ require "rspec/wait"
82
+ #require 'pusher-fake/support/base'
83
+
84
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
85
+
86
+ RSpec.configure do |config|
87
+ config.color = true
88
+ config.fail_fast = ENV['FAIL_FAST'] || false
89
+ config.fixture_path = File.join(File.expand_path(File.dirname(__FILE__)), "fixtures")
90
+ config.infer_spec_type_from_file_location!
91
+ config.mock_with :rspec
92
+ config.raise_errors_for_deprecations!
93
+
94
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
95
+ # examples within a transaction, comment the following line or assign false
96
+ # instead of true.
97
+ config.use_transactional_fixtures = true
98
+
99
+ config.after :each do
100
+ Rails.cache.clear
101
+ end
102
+
103
+ config.after(:each) do |example|
104
+ unless example.exception
105
+ #Object.send(:remove_const, :Application) rescue nil
106
+ ObjectSpace.each_object(Class).each do |klass|
107
+ if klass < HyperMesh::Regulation
108
+ klass.instance_variables.each { |v| klass.instance_variable_set(v, nil) }
109
+ end
110
+ end
111
+ PusherFake::Channel.reset if defined? PusherFake
112
+ end
113
+ end
114
+
115
+ config.filter_run_including focus: true
116
+ config.filter_run_excluding opal: true
117
+ config.run_all_when_everything_filtered = true
118
+ end
119
+
120
+ FACTORY_GIRL = false
121
+
122
+ #require 'rails_helper'
123
+ require 'rspec'
124
+ require 'rspec/expectations'
125
+ begin
126
+ require 'factory_girl_rails'
127
+ rescue LoadError
128
+ end
129
+ require 'shoulda/matchers'
130
+ require 'database_cleaner'
131
+ require 'capybara/rspec'
132
+ require 'capybara/rails'
133
+ require 'support/component_helpers'
134
+ require 'capybara/poltergeist'
135
+ require 'selenium-webdriver'
136
+
137
+ module React
138
+ module IsomorphicHelpers
139
+ def self.load_context(ctx, controller, name = nil)
140
+ @context = Context.new("#{controller.object_id}-#{Time.now.to_i}", ctx, controller, name)
141
+ end
142
+ end
143
+ end
144
+
145
+ #Capybara.default_max_wait_time = 4.seconds
146
+
147
+ Capybara.server = :puma
148
+
149
+ # The following is deprecated and replaced by the above... just make sure it works
150
+ # before removing
151
+ # Capybara.server { |app, port|
152
+ # require 'puma'
153
+ # Puma::Server.new(app).tap do |s|
154
+ # s.add_tcp_listener Capybara.server_host, port
155
+ # end.run.join
156
+ # }
157
+
158
+ module WaitForAjax
159
+
160
+ def wait_for_ajax
161
+ Timeout.timeout(Capybara.default_max_wait_time) do
162
+ begin
163
+ sleep 0.25
164
+ end until finished_all_ajax_requests?
165
+ end
166
+ end
167
+
168
+ def running?
169
+ result = page.evaluate_script("(function(active) {console.log('jquery is active? '+active); return active})(jQuery.active)")
170
+ result && !result.zero?
171
+ rescue Exception => e
172
+ puts "wait_for_ajax failed while testing state of jQuery.active: #{e}"
173
+ end
174
+
175
+ def finished_all_ajax_requests?
176
+ unless running?
177
+ sleep 0.25 # this was 1 second, not sure if its necessary to be so long...
178
+ !running?
179
+ end
180
+ rescue Capybara::NotSupportedByDriverError
181
+ true
182
+ rescue Exception => e
183
+ e.message == "jQuery is not defined"
184
+ end
185
+
186
+ end
187
+
188
+ RSpec.configure do |config|
189
+ config.include WaitForAjax
190
+ end
191
+
192
+ RSpec.configure do |config|
193
+ # rspec-expectations config goes here. You can use an alternate
194
+ # assertion/expectation library such as wrong or the stdlib/minitest
195
+ # assertions if you prefer.
196
+ config.expect_with :rspec do |expectations|
197
+ # Enable only the newer, non-monkey-patching expect syntax.
198
+ # For more details, see:
199
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
200
+ expectations.syntax = [:should, :expect]
201
+ end
202
+
203
+ # rspec-mocks config goes here. You can use an alternate test double
204
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
205
+ config.mock_with :rspec do |mocks|
206
+ # Enable only the newer, non-monkey-patching expect syntax.
207
+ # For more details, see:
208
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
209
+ mocks.syntax = :expect
210
+
211
+ # Prevents you from mocking or stubbing a method that does not exist on
212
+ # a real object. This is generally recommended.
213
+ mocks.verify_partial_doubles = true
214
+ end
215
+
216
+ config.include FactoryGirl::Syntax::Methods if defined? FactoryGirl
217
+
218
+ config.use_transactional_fixtures = false
219
+
220
+ Capybara.default_max_wait_time = 10.seconds
221
+
222
+ config.before(:suite) do
223
+ DatabaseCleaner.clean_with(:truncation)
224
+ end
225
+
226
+ config.before(:each) do
227
+ DatabaseCleaner.strategy = :transaction
228
+ end
229
+
230
+ config.before(:each) do |x|
231
+ #puts " RUNNING #{x.full_description}"
232
+ end
233
+
234
+ config.before(:each, :js => true) do
235
+ DatabaseCleaner.strategy = :truncation
236
+ end
237
+
238
+ config.before(:each, :js => true) do
239
+ size_window
240
+ end
241
+
242
+ config.before(:each) do
243
+ DatabaseCleaner.start
244
+ end
245
+
246
+ config.after(:each) do |example|
247
+ unless example.exception
248
+ # Clear session data
249
+ Capybara.reset_sessions!
250
+ # Rollback transaction
251
+ DatabaseCleaner.clean
252
+ end
253
+ end
254
+
255
+ config.after(:all, :js => true) do
256
+ #size_window(:default)
257
+ end
258
+
259
+ config.after(:each, :js => true) do
260
+ page.instance_variable_set("@hyper_spec_mounted", false)
261
+ end
262
+
263
+ config.include Capybara::DSL
264
+
265
+ Capybara.register_driver :chrome do |app|
266
+ #caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"excludeSwitches" => [ "ignore-certificate-errors" ]})
267
+ caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"args" => [ "--window-size=200,200" ]})
268
+ Capybara::Selenium::Driver.new(app, :browser => :chrome, :desired_capabilities => caps)
269
+ end
270
+
271
+ options = {
272
+ js_errors: false,
273
+ timeout: 180,
274
+ inspector: true,
275
+ phantomjs_options: ['--load-images=no', '--ignore-ssl-errors=yes']
276
+ }
277
+ options.merge!({phantomjs_logger: StringIO.new, logger: StringIO.new,}) unless ENV['SHOW_LOGS']
278
+ Capybara.register_driver :poltergeist do |app|
279
+ Capybara::Poltergeist::Driver.new(app, options)
280
+ end
281
+
282
+ class Selenium::WebDriver::Firefox::Profile
283
+
284
+ def self.firebug_version
285
+ @firebug_version ||= '2.0.13-fx'
286
+ end
287
+
288
+ def self.firebug_version=(version)
289
+ @firebug_version = version
290
+ end
291
+
292
+ def frame_position
293
+ @frame_position ||= 'detached'
294
+ end
295
+
296
+ def frame_position=(position)
297
+ @frame_position = ["left", "right", "top", "detached"].detect do |side|
298
+ position && position[0].downcase == side[0]
299
+ end || "detached"
300
+ end
301
+
302
+ def enable_firebug(version = nil)
303
+ version ||= Selenium::WebDriver::Firefox::Profile.firebug_version
304
+ add_extension(File.expand_path("../bin/firebug-#{version}.xpi", __FILE__))
305
+
306
+ # For some reason, Firebug seems to trigger the Firefox plugin check
307
+ # (navigating to https://www.mozilla.org/en-US/plugincheck/ at startup).
308
+ # This prevents it. See http://code.google.com/p/selenium/issues/detail?id=4619.
309
+ self["extensions.blocklist.enabled"] = false
310
+
311
+ # Prevent "Welcome!" tab
312
+ self["extensions.firebug.showFirstRunPage"] = false
313
+
314
+ # Enable for all sites.
315
+ self["extensions.firebug.allPagesActivation"] = "on"
316
+
317
+ # Enable all features.
318
+ ['console', 'net', 'script'].each do |feature|
319
+ self["extensions.firebug.#{feature}.enableSites"] = true
320
+ end
321
+
322
+ # Closed by default, will open detached.
323
+ self["extensions.firebug.framePosition"] = frame_position
324
+ self["extensions.firebug.previousPlacement"] = 3
325
+ self["extensions.firebug.defaultPanelName"] = "console"
326
+
327
+ # Disable native "Inspect Element" menu item.
328
+ self["devtools.inspector.enabled"] = false
329
+ self["extensions.firebug.hideDefaultInspector"] = true
330
+ end
331
+ end
332
+
333
+ Capybara.register_driver :selenium_with_firebug do |app|
334
+ profile = Selenium::WebDriver::Firefox::Profile.new
335
+ profile.frame_position = ENV['DRIVER'] && ENV['DRIVER'][2]
336
+ profile.enable_firebug
337
+ Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile)
338
+ end
339
+
340
+ Capybara.javascript_driver = :poltergeist
341
+
342
+ Capybara.register_driver :chrome do |app|
343
+ Capybara::Selenium::Driver.new(app, :browser => :chrome)
344
+ end
345
+
346
+ if ENV['DRIVER'] =~ /^ff/
347
+ Capybara.javascript_driver = :selenium_with_firebug
348
+ elsif ENV['DRIVER'] == 'chrome'
349
+ Capybara.javascript_driver = :chrome
350
+ else
351
+ Capybara.javascript_driver = :poltergeist
352
+ end
353
+
354
+ include ComponentTestHelpers
355
+
356
+ end
357
+
358
+ FactoryGirl.define do
359
+
360
+ sequence :seq_number do |n|
361
+ " #{n}"
362
+ end
363
+
364
+ end if defined? FactoryGirl
365
+
366
+ end
@@ -0,0 +1,351 @@
1
+ # see component_test_helpers_spec.rb for examples
2
+
3
+ require 'parser/current'
4
+ require 'unparser'
5
+ #require 'pry'
6
+
7
+ module ComponentTestHelpers
8
+
9
+ def self.compile_to_opal(&block)
10
+ Opal.compile(block.source.split("\n")[1..-2].join("\n"))
11
+ end
12
+
13
+
14
+ TOP_LEVEL_COMPONENT_PATCH = lambda { |&block| Opal.compile(block.source.split("\n")[1..-2].join("\n"))}.call do #ComponentTestHelpers.compile_to_opal do
15
+ module React
16
+ class TopLevelRailsComponent
17
+
18
+ class << self
19
+ attr_accessor :event_history
20
+
21
+ def callback_history_for(proc_name)
22
+ event_history[proc_name]
23
+ end
24
+
25
+ def last_callback_for(proc_name)
26
+ event_history[proc_name].last
27
+ end
28
+
29
+ def clear_callback_history_for(proc_name)
30
+ event_history[proc_name] = []
31
+ end
32
+
33
+ def event_history_for(event_name)
34
+ event_history["_on#{event_name.event_camelize}"]
35
+ end
36
+
37
+ def last_event_for(event_name)
38
+ event_history["_on#{event_name.event_camelize}"].last
39
+ end
40
+
41
+ def clear_event_history_for(event_name)
42
+ event_history["_on#{event_name.event_camelize}"] = []
43
+ end
44
+
45
+ end
46
+
47
+ def component
48
+ return @component if @component
49
+ paths_searched = []
50
+ if params.component_name.start_with? "::"
51
+ paths_searched << params.component_name.gsub(/^\:\:/,"")
52
+ @component = params.component_name.gsub(/^\:\:/,"").split("::").inject(Module) { |scope, next_const| scope.const_get(next_const, false) } rescue nil
53
+ return @component if @component && @component.method_defined?(:render)
54
+ else
55
+ self.class.search_path.each do |path|
56
+ # try each path + params.controller + params.component_name
57
+ paths_searched << "#{path.name + '::' unless path == Module}#{params.controller}::#{params.component_name}"
58
+ @component = "#{params.controller}::#{params.component_name}".split("::").inject(path) { |scope, next_const| scope.const_get(next_const, false) } rescue nil
59
+ return @component if @component && @component.method_defined?(:render)
60
+ end
61
+ self.class.search_path.each do |path|
62
+ # then try each path + params.component_name
63
+ paths_searched << "#{path.name + '::' unless path == Module}#{params.component_name}"
64
+ @component = "#{params.component_name}".split("::").inject(path) { |scope, next_const| scope.const_get(next_const, false) } rescue nil
65
+ return @component if @component && @component.method_defined?(:render)
66
+ end
67
+ end
68
+ @component = nil
69
+ raise "Could not find component class '#{params.component_name}' for params.controller '#{params.controller}' in any component directory. Tried [#{paths_searched.join(", ")}]"
70
+ end
71
+
72
+ before_mount do
73
+ TopLevelRailsComponent.event_history = Hash.new {|h,k| h[k] = [] }
74
+ component.validator.rules.each do |name, rules|
75
+ if rules[:type] == Proc
76
+ TopLevelRailsComponent.event_history[name] = []
77
+ params.render_params[name] = lambda { |*args| TopLevelRailsComponent.event_history[name] << args.collect { |arg| Native(arg).to_n } }
78
+ end
79
+ end
80
+ end
81
+
82
+ def render
83
+ present component, params.render_params
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def build_test_url_for(controller)
90
+
91
+ unless controller
92
+ Object.const_set("ReactTestController", Class.new(ApplicationController)) unless defined?(::ReactTestController)
93
+ controller = ::ReactTestController
94
+ end
95
+
96
+ route_root = controller.name.gsub(/Controller$/,"").underscore
97
+
98
+ unless controller.method_defined? :test
99
+ controller.class_eval do
100
+ define_method(:test) do
101
+ route_root = self.class.name.gsub(/Controller$/,"").underscore
102
+ test_params = Rails.cache.read("/#{route_root}/#{params[:id]}")
103
+ @component_name = test_params[0]
104
+ @component_params = test_params[1]
105
+ render_params = test_params[2]
106
+ render_on = render_params.delete(:render_on) || :both
107
+ mock_time = render_params.delete(:mock_time)
108
+ style_sheet = render_params.delete(:style_sheet)
109
+ javascript = render_params.delete(:javascript)
110
+ code = render_params.delete(:code)
111
+ page = "<%= react_component @component_name, @component_params, { prerender: false } %>" # false should be: "#{render_on != :client_only} } %>" but its not working in the gem testing harness
112
+ page = "<script type='text/javascript'>\n#{TOP_LEVEL_COMPONENT_PATCH}\n</script>\n#{page}"
113
+
114
+ if code
115
+ page = "<script type='text/javascript'>\n#{code}\n</script>\n"+page
116
+ end
117
+
118
+ #TODO figure out how to auto insert this line???? something like:
119
+ #page = "<%= javascript_include_tag 'reactrb-router' %>\n#{page}"
120
+
121
+ if (render_on != :server_only && !render_params[:layout]) || javascript
122
+ #page = "<script src='/assets/application.js?ts=#{Time.now.to_f}'></script>\n"+page
123
+ page = "<%= javascript_include_tag '#{javascript || 'application'}' %>\n"+page
124
+ end
125
+ if mock_time || (defined?(Timecop) && Timecop.top_stack_item)
126
+ puts "********** WARNING LOLEX NOT AVAILABLE TIME ON CLIENT WILL NOT MATCH SERVER **********"
127
+ # unix_millis = ((mock_time || Time.now).to_f * 1000.0).to_i
128
+ # page = "<%= javascript_include_tag 'spec/libs/lolex' %>\n"+
129
+ # "<script type='text/javascript'>\n"+
130
+ # " window.original_setInterval = setInterval;\n"+
131
+ # " window.lolex_clock = lolex.install(#{unix_millis});\n"+
132
+ # " window.original_setInterval(function() {window.lolex_clock.tick(10)}, 10);\n"+
133
+ # "</script>\n"+page
134
+ end
135
+ if !render_params[:layout] || style_sheet
136
+ page = "<%= stylesheet_link_tag '#{style_sheet || 'application'}' rescue nil %>\n"+page
137
+ end
138
+ if render_on == :server_only # so that test helper wait_for_ajax works
139
+ page = "<script type='text/javascript'>window.jQuery = {'active': 0}</script>\n#{page}"
140
+ else
141
+ page = "<%= javascript_include_tag 'jquery' %>\n<%= javascript_include_tag 'jquery_ujs' %>\n#{page}"
142
+ end
143
+ page = "<script type='text/javascript'>go = function() {window.hyper_spec_waiting_for_go = false}</script>\n#{page}"
144
+ title = view_context.escape_javascript(ComponentTestHelpers.current_example.description)
145
+ title = "#{title}...continued." if ComponentTestHelpers.description_displayed
146
+ page = "<script type='text/javascript'>console.log(console.log('%c#{title}','color:green; font-weight:bold; font-size: 200%'))</script>\n#{page}"
147
+ ComponentTestHelpers.description_displayed = true
148
+ render_params[:inline] = page
149
+ render render_params
150
+ end
151
+ end
152
+
153
+ # test_routes = Proc.new do
154
+ # get "/#{route_root}/:id", to: "#{route_root}#test"
155
+ # end
156
+ # Rails.application.routes.eval_block(test_routes)
157
+
158
+ begin
159
+ routes = Rails.application.routes
160
+ routes.disable_clear_and_finalize = true
161
+ routes.clear!
162
+ routes.draw do
163
+ get "/#{route_root}/:id", to: "#{route_root}#test"
164
+ end
165
+ Rails.application.routes_reloader.paths.each{ |path| load(path) }
166
+ routes.finalize!
167
+ ActiveSupport.on_load(:action_controller) { routes.finalize! }
168
+ ensure
169
+ routes.disable_clear_and_finalize = false
170
+ end
171
+ end
172
+
173
+ "/#{route_root}/#{@test_id = (@test_id || 0) + 1}"
174
+
175
+ end
176
+
177
+ def isomorphic(&block)
178
+ yield
179
+ on_client(&block)
180
+ end
181
+
182
+ def evaluate_ruby(str="", opts={}, &block)
183
+ insure_mount
184
+ str = "#{str}\n#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}" if block
185
+ js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
186
+ JSON.parse(evaluate_script("[#{js}].$to_json()"), opts).first
187
+ end
188
+
189
+ def expect_evaluate_ruby(str = '', opts = {}, &block)
190
+ insure_mount
191
+ expect(evaluate_ruby(add_opal_block(str, block), opts))
192
+ end
193
+
194
+ def add_opal_block(str, block)
195
+ # big assumption here is that we are going to follow this with a .to
196
+ # hence .children.first followed by .children.last
197
+ # probably should do some kind of "search" to make this work nicely
198
+ return str unless block
199
+ "#{str}\n"\
200
+ "#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.first.children.last}"
201
+ end
202
+
203
+ def expect_promise(str = '', opts = {}, &block)
204
+ insure_mount
205
+ str = add_opal_block(str, block)
206
+ str = "#{str}.then { |args| args = [args]; `window.hyper_spec_promise_result = args` }"
207
+ js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
208
+ page.evaluate_script("window.hyper_spec_promise_result = false")
209
+ page.execute_script(js)
210
+ Timeout.timeout(Capybara.default_max_wait_time) do
211
+ loop do
212
+ sleep 0.25
213
+ break if page.evaluate_script("!!window.hyper_spec_promise_result")
214
+ end
215
+ end
216
+ expect(JSON.parse(page.evaluate_script("window.hyper_spec_promise_result.$to_json()"), opts).first)
217
+ end
218
+
219
+ def ppr(str)
220
+ js = Opal.compile(str).gsub("\n","").gsub("(Opal);","(Opal)")
221
+ execute_script("console.log(#{js})")
222
+ end
223
+
224
+
225
+ def on_client(&block)
226
+ @client_code = "#{@client_code}#{Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last}\n"
227
+ end
228
+
229
+ def debugger
230
+ `debugger`
231
+ nil
232
+ end
233
+
234
+ class << self
235
+ attr_accessor :current_example
236
+ attr_accessor :description_displayed
237
+ def display_example_description
238
+ "<script type='text/javascript'>console.log(console.log('%c#{current_example.description}','color:green; font-weight:bold; font-size: 200%'))</script>"
239
+ end
240
+ end
241
+
242
+ def insure_mount
243
+ # rescue in case page is not defined...
244
+ mount unless page.instance_variable_get("@hyper_spec_mounted") rescue nil
245
+ end
246
+
247
+ def mount(component_name = nil, params = nil, opts = {}, &block)
248
+ unless params
249
+ params = opts
250
+ opts = {}
251
+ end
252
+ test_url = build_test_url_for(opts.delete(:controller))
253
+ if block || @client_code || component_name.nil?
254
+ block_with_helpers = <<-code
255
+ module ComponentHelpers
256
+ def self.js_eval(s)
257
+ `eval(s)`
258
+ end
259
+ def self.add_class(class_name, styles={})
260
+ style = styles.collect { |attr, value| "\#{attr.dasherize}:\#{value}"}.join("; ")
261
+ s = "<style type='text/css'> .\#{class_name}{ \#{style} } </style>"
262
+ `$(\#{s}).appendTo("head");`
263
+ end
264
+ end
265
+ class React::Component::HyperTestDummy < React::Component::Base
266
+ def render; end
267
+ end
268
+ #{@client_code}
269
+ #{Unparser.unparse(Parser::CurrentRuby.parse(block.source).children.last) if block}
270
+ code
271
+ opts[:code] = Opal.compile(block_with_helpers)
272
+ end
273
+ component_name ||= 'React::Component::HyperTestDummy'
274
+ Rails.cache.write(test_url, [component_name, params, opts])
275
+ visit test_url
276
+ wait_for_ajax unless opts[:no_wait]
277
+ page.instance_variable_set("@hyper_spec_mounted", true)
278
+ end
279
+
280
+ [:callback_history_for, :last_callback_for, :clear_callback_history_for, :event_history_for, :last_event_for, :clear_event_history_for].each do |method|
281
+ define_method(method) { |event_name| evaluate_script("Opal.React.TopLevelRailsComponent.$#{method}('#{event_name}')") }
282
+ end
283
+
284
+ def run_on_client(&block)
285
+ script = Opal.compile(Unparser.unparse Parser::CurrentRuby.parse(block.source).children.last)
286
+ execute_script(script)
287
+ end
288
+
289
+ def open_in_chrome
290
+ if false && ['linux', 'freebsd'].include?(`uname`.downcase)
291
+ `google-chrome http://#{page.server.host}:#{page.server.port}#{page.current_path}`
292
+ else
293
+ `open http://#{page.server.host}:#{page.server.port}#{page.current_path}`
294
+ end
295
+ while true
296
+ sleep 1.hour
297
+ end
298
+ end
299
+
300
+ def pause(message = nil)
301
+ if message
302
+ puts message
303
+ page.evaluate_ruby "puts #{message.inspect}.to_s + ' (type go() to continue)'"
304
+ end
305
+ page.evaluate_script("window.hyper_spec_waiting_for_go = true")
306
+ loop do
307
+ sleep 0.25
308
+ break unless page.evaluate_script("window.hyper_spec_waiting_for_go")
309
+ end
310
+ end
311
+
312
+ def size_window(width=nil, height=nil)
313
+ width, height = width if width.is_a? Array
314
+ portrait = true if height == :portrait
315
+ case width
316
+ when :small
317
+ width, height = [480, 320]
318
+ when :mobile
319
+ width, height = [640, 480]
320
+ when :tablet
321
+ width, height = [960, 640]
322
+ when :large
323
+ width, height = [1920, 6000]
324
+ when :default, nil
325
+ width, height = [1024, 768]
326
+ end
327
+ if portrait
328
+ width, height = [height, width]
329
+ end
330
+ if page.driver.browser.respond_to?(:manage)
331
+ page.driver.browser.manage.window.resize_to(width, height)
332
+ elsif page.driver.respond_to?(:resize)
333
+ page.driver.resize(width, height)
334
+ end
335
+ end
336
+
337
+ end
338
+
339
+ RSpec.configure do |config|
340
+ config.before(:each) do |example|
341
+ ComponentTestHelpers.current_example = example
342
+ ComponentTestHelpers.description_displayed = false
343
+ end
344
+ config.before(:all) do
345
+ ActiveRecord::Base.class_eval do
346
+ def attributes_on_client(page)
347
+ page.evaluate_ruby("#{self.class.name}.find(#{id}).attributes", symbolize_names: true)
348
+ end
349
+ end
350
+ end
351
+ end