bootstrap_form 4.4.0 → 5.1.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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +48 -0
  3. data/.gitignore +28 -3
  4. data/.rubocop.yml +19 -15
  5. data/CHANGELOG.md +82 -1
  6. data/CONTRIBUTING.md +73 -12
  7. data/Dangerfile +5 -7
  8. data/Dockerfile +21 -0
  9. data/Gemfile +8 -11
  10. data/README.md +829 -82
  11. data/RELEASING.md +5 -10
  12. data/UPGRADE-4.0.md +1 -1
  13. data/UPGRADE-5.0.md +25 -0
  14. data/bootstrap_form.gemspec +8 -5
  15. data/demo/.ruby-version +1 -0
  16. data/demo/Gemfile +80 -0
  17. data/demo/Gemfile.lock +261 -0
  18. data/demo/Procfile.dev +2 -0
  19. data/demo/app/assets/builds/.keep +0 -0
  20. data/demo/app/assets/builds/application.js.LICENSE.txt +9 -0
  21. data/demo/app/assets/config/manifest.js +2 -2
  22. data/demo/app/assets/stylesheets/actiontext.css +31 -0
  23. data/demo/app/assets/stylesheets/application.scss +1 -1
  24. data/demo/app/controllers/bootstrap_controller.rb +17 -2
  25. data/demo/app/controllers/users_controller.rb +9 -0
  26. data/demo/app/helpers/bootstrap_helper.rb +5 -5
  27. data/demo/app/javascript/application.js +3 -0
  28. data/demo/app/models/skill.rb +15 -0
  29. data/demo/app/models/user.rb +14 -0
  30. data/demo/app/views/active_storage/blobs/_blob.html.erb +1 -1
  31. data/demo/app/views/bootstrap/form.html.erb +13 -0
  32. data/demo/app/views/layouts/action_text/contents/_content.html.erb +3 -0
  33. data/demo/app/views/layouts/application.html.erb +28 -20
  34. data/demo/bin/dev +9 -0
  35. data/demo/config/environments/development.rb +3 -3
  36. data/demo/config/puma.rb +2 -2
  37. data/demo/config/routes.rb +1 -0
  38. data/demo/db/schema.rb +31 -16
  39. data/demo/doc/screenshots/bootstrap/index/00_horizontal_form.png +0 -0
  40. data/demo/doc/screenshots/bootstrap/index/01_with_validation_error.png +0 -0
  41. data/demo/doc/screenshots/bootstrap/index/02_inline_form.png +0 -0
  42. data/demo/doc/screenshots/bootstrap/index/03_simple_action_text_example.png +0 -0
  43. data/demo/doc/screenshots/bootstrap/index/04_floating_labels.png +0 -0
  44. data/demo/doc/screenshots/bootstrap/readme/00_example.png +0 -0
  45. data/demo/doc/screenshots/bootstrap/readme/01_example.png +0 -0
  46. data/demo/doc/screenshots/bootstrap/readme/02_example.png +0 -0
  47. data/demo/doc/screenshots/bootstrap/readme/03_example.png +0 -0
  48. data/demo/doc/screenshots/bootstrap/readme/04_example.png +0 -0
  49. data/demo/doc/screenshots/bootstrap/readme/05_example.png +0 -0
  50. data/demo/doc/screenshots/bootstrap/readme/06_example.png +0 -0
  51. data/demo/doc/screenshots/bootstrap/readme/07_example.png +0 -0
  52. data/demo/doc/screenshots/bootstrap/readme/08_example.png +0 -0
  53. data/demo/doc/screenshots/bootstrap/readme/09_example.png +0 -0
  54. data/demo/doc/screenshots/bootstrap/readme/10_example.png +0 -0
  55. data/demo/doc/screenshots/bootstrap/readme/11_example.png +0 -0
  56. data/demo/doc/screenshots/bootstrap/readme/12_example.png +0 -0
  57. data/demo/doc/screenshots/bootstrap/readme/13_example.png +0 -0
  58. data/demo/doc/screenshots/bootstrap/readme/14_example.png +0 -0
  59. data/demo/doc/screenshots/bootstrap/readme/15_example.png +0 -0
  60. data/demo/doc/screenshots/bootstrap/readme/16_example.png +0 -0
  61. data/demo/doc/screenshots/bootstrap/readme/17_example.png +0 -0
  62. data/demo/doc/screenshots/bootstrap/readme/18_example.png +0 -0
  63. data/demo/doc/screenshots/bootstrap/readme/19_example.png +0 -0
  64. data/demo/doc/screenshots/bootstrap/readme/20_example.png +0 -0
  65. data/demo/doc/screenshots/bootstrap/readme/21_example.png +0 -0
  66. data/demo/doc/screenshots/bootstrap/readme/22_example.png +0 -0
  67. data/demo/doc/screenshots/bootstrap/readme/23_example.png +0 -0
  68. data/demo/doc/screenshots/bootstrap/readme/24_example.png +0 -0
  69. data/demo/doc/screenshots/bootstrap/readme/25_example.png +0 -0
  70. data/demo/doc/screenshots/bootstrap/readme/26_example.png +0 -0
  71. data/demo/doc/screenshots/bootstrap/readme/27_example.png +0 -0
  72. data/demo/doc/screenshots/bootstrap/readme/28_example.png +0 -0
  73. data/demo/doc/screenshots/bootstrap/readme/29_example.png +0 -0
  74. data/demo/doc/screenshots/bootstrap/readme/30_example.png +0 -0
  75. data/demo/doc/screenshots/bootstrap/readme/31_example.png +0 -0
  76. data/demo/doc/screenshots/bootstrap/readme/32_example.png +0 -0
  77. data/demo/doc/screenshots/bootstrap/readme/33_example.png +0 -0
  78. data/demo/doc/screenshots/bootstrap/readme/34_example.png +0 -0
  79. data/demo/doc/screenshots/bootstrap/readme/35_example.png +0 -0
  80. data/demo/doc/screenshots/bootstrap/readme/36_example.png +0 -0
  81. data/demo/doc/screenshots/bootstrap/readme/37_example.png +0 -0
  82. data/demo/doc/screenshots/bootstrap/readme/38_example.png +0 -0
  83. data/demo/doc/screenshots/bootstrap/readme/39_example.png +0 -0
  84. data/demo/doc/screenshots/bootstrap/readme/40_example.png +0 -0
  85. data/demo/doc/screenshots/bootstrap/readme/41_example.png +0 -0
  86. data/demo/doc/screenshots/bootstrap/readme/42_example.png +0 -0
  87. data/demo/doc/screenshots/bootstrap/readme/43_example.png +0 -0
  88. data/demo/doc/screenshots/bootstrap/readme/44_example.png +0 -0
  89. data/demo/doc/screenshots/bootstrap/readme/45_example.png +0 -0
  90. data/demo/doc/screenshots/bootstrap/readme/46_example.png +0 -0
  91. data/demo/doc/screenshots/bootstrap/readme/47_example.png +0 -0
  92. data/demo/doc/screenshots/bootstrap/readme/48_example.png +0 -0
  93. data/demo/doc/screenshots/bootstrap/readme/49_example.png +0 -0
  94. data/demo/doc/screenshots/bootstrap/readme/50_example.png +0 -0
  95. data/demo/package.json +10 -6
  96. data/demo/test/application_system_test_case.rb +8 -0
  97. data/demo/test/controllers/bootstrap_controller_test.rb +8 -0
  98. data/demo/test/controllers/users_controller_test.rb +13 -0
  99. data/demo/test/fixtures/users.yml +2 -0
  100. data/demo/test/system/bootstrap_test.rb +84 -0
  101. data/demo/test/test_helper.rb +10 -0
  102. data/demo/webpack.config.js +20 -0
  103. data/demo/yarn.lock +4063 -3144
  104. data/docker-compose.yml +49 -0
  105. data/gemfiles/5.2.gemfile +2 -15
  106. data/gemfiles/6.0.gemfile +2 -17
  107. data/gemfiles/6.1.gemfile +4 -0
  108. data/gemfiles/7.0.gemfile +6 -0
  109. data/gemfiles/edge.gemfile +2 -17
  110. data/lib/bootstrap_form/action_view_extensions/form_helper.rb +1 -1
  111. data/lib/bootstrap_form/components/hints.rb +13 -4
  112. data/lib/bootstrap_form/components/labels.rb +2 -2
  113. data/lib/bootstrap_form/components/validation.rb +1 -1
  114. data/lib/bootstrap_form/configuration.rb +22 -0
  115. data/lib/bootstrap_form/form_builder.rb +10 -12
  116. data/lib/bootstrap_form/form_group.rb +26 -11
  117. data/lib/bootstrap_form/form_group_builder.rb +6 -8
  118. data/lib/bootstrap_form/helpers/bootstrap.rb +17 -12
  119. data/lib/bootstrap_form/inputs/base.rb +5 -5
  120. data/lib/bootstrap_form/inputs/check_box.rb +11 -23
  121. data/lib/bootstrap_form/inputs/collection_check_boxes.rb +5 -1
  122. data/lib/bootstrap_form/inputs/collection_select.rb +2 -1
  123. data/lib/bootstrap_form/inputs/file_field.rb +3 -15
  124. data/lib/bootstrap_form/inputs/grouped_collection_select.rb +2 -1
  125. data/lib/bootstrap_form/inputs/radio_button.rb +17 -30
  126. data/lib/bootstrap_form/inputs/select.rb +1 -0
  127. data/lib/bootstrap_form/inputs/time_zone_select.rb +1 -0
  128. data/lib/bootstrap_form/version.rb +1 -1
  129. data/lib/bootstrap_form.rb +17 -7
  130. metadata +94 -16
  131. data/.travis.yml +0 -42
  132. data/demo/config/initializers/assets.rb +0 -14
  133. data/gemfiles/5.0.gemfile +0 -18
  134. data/gemfiles/5.1.gemfile +0 -17
@@ -6,12 +6,12 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
7
 
8
8
  <!-- Bootstrap CSS -->
9
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
10
-
9
+ <!-- CSS only -->
10
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
11
11
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/codemirror.min.css">
12
12
 
13
13
  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
14
- <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
14
+ <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', defer: true %>
15
15
 
16
16
  <style type="text/css">
17
17
  .example {
@@ -19,8 +19,11 @@
19
19
  border: .2rem solid #f7f7f9;
20
20
  margin-bottom: 3em;
21
21
  }
22
- form {
23
- margin-bottom: 1.5em;
22
+ .toggle {
23
+ margin-top: 1.5em;
24
+ }
25
+ .code {
26
+ margin-top: 1rem;
24
27
  }
25
28
  .CodeMirror {
26
29
  border: 1px solid #eee;
@@ -34,6 +37,7 @@
34
37
 
35
38
  <title>Hello, world!</title>
36
39
  <%= csrf_meta_tags %>
40
+ <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
37
41
  </head>
38
42
 
39
43
  <body>
@@ -42,26 +46,30 @@
42
46
  </div>
43
47
 
44
48
  <!-- Optional JavaScript -->
45
- <!-- jQuery first, then Popper.js, then Bootstrap JS -->
46
- <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
47
- <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
48
- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
49
-
49
+ <!-- JavaScript Bundle with Popper -->
50
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
50
51
  <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/codemirror.min.js"></script>
51
52
  <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/mode/htmlmixed/htmlmixed.min.js"></script>
52
53
  <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.33.0/mode/xml/xml.min.js"></script>
53
54
 
54
55
  <script type="text/javascript">
55
- $(document).on("click", "button.toggle", function(){
56
- var example = $(this).parent(".example");
57
- $(this).hide();
58
- $(".code", example).show()
59
- CodeMirror.fromTextArea($("textarea.codemirror", example)[0], {
60
- mode: "htmlmixed",
61
- tabSize: 2,
62
- lineNumbers: true,
63
- viewportMargin: Infinity
64
- })
56
+ const buttons = document.querySelectorAll('button.toggle');
57
+ const buttonsArray = Array.prototype.slice.call(buttons);
58
+ buttonsArray.forEach(function(elem) {
59
+ elem.addEventListener('click', function() {
60
+ const example = this.closest('.example');
61
+ if (example.querySelector('.code').style.display === "block") {
62
+ example.querySelector('.code').style.display = "none";
63
+ } else {
64
+ example.querySelector('.code').style.display = "block";
65
+ }
66
+ CodeMirror.fromTextArea(example.querySelector('textarea.codemirror'), {
67
+ mode: 'htmlmixed',
68
+ tabSize: 2,
69
+ lineNumbers: true,
70
+ viewportMargin: Infinity,
71
+ });
72
+ });
65
73
  });
66
74
  </script>
67
75
  </body>
data/demo/bin/dev ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if ! command -v foreman &> /dev/null
4
+ then
5
+ echo "Installing foreman..."
6
+ gem install foreman
7
+ fi
8
+
9
+ foreman start -f Procfile.dev
@@ -1,6 +1,6 @@
1
1
  Rails.application.configure do
2
2
  # Verifies that versions and hashed value of the package contents in the project's package.json
3
- config.webpacker.check_yarn_integrity = true
3
+ # config.webpacker.check_yarn_integrity = true
4
4
  # Settings specified here will take precedence over those in config/application.rb.
5
5
 
6
6
  # In the development environment your application's code is reloaded on
@@ -46,10 +46,10 @@ Rails.application.configure do
46
46
  # Debug mode disables concatenation and preprocessing of assets.
47
47
  # This option may cause significant delays in view rendering with a large
48
48
  # number of complex assets.
49
- config.assets.debug = true
49
+ # config.assets.debug = true
50
50
 
51
51
  # Suppress logger output for asset requests.
52
- config.assets.quiet = true
52
+ # config.assets.quiet = true
53
53
 
54
54
  # Raises error for missing translations
55
55
  # config.action_view.raise_on_missing_translations = true
data/demo/config/puma.rb CHANGED
@@ -4,12 +4,12 @@
4
4
  # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
5
  # and maximum; this matches the default thread size of Active Record.
6
6
  #
7
- threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
7
+ threads_count = ENV.fetch("RAILS_MAX_THREADS", 5)
8
8
  threads threads_count, threads_count
9
9
 
10
10
  # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
11
11
  #
12
- port ENV.fetch("PORT") { 3000 }
12
+ port ENV.fetch("PORT", 3000)
13
13
 
14
14
  # Specifies the `environment` that Puma will run in.
15
15
  #
@@ -1,4 +1,5 @@
1
1
  Dummy::Application.routes.draw do
2
+ get "fragment" => "bootstrap#fragment", as: :fragment
2
3
  resources :users
3
4
 
4
5
  root to: "bootstrap#form"
data/demo/db/schema.rb CHANGED
@@ -2,32 +2,32 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # This file is the source Rails uses to define your schema when running `rails
6
- # db:schema:load`. When creating a new database, `rails db:schema:load` tends to
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
7
  # be faster and is potentially less error prone than running all of your
8
8
  # migrations from scratch. Old migrations may fail to apply correctly if those
9
9
  # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2019_01_26_192508) do
13
+ ActiveRecord::Schema.define(version: 2022_01_09_230956) do
14
14
 
15
15
  create_table "action_text_rich_texts", force: :cascade do |t|
16
16
  t.string "name", null: false
17
- t.text "body", limit: 16777215
17
+ t.text "body"
18
18
  t.string "record_type", null: false
19
- t.integer "record_id", null: false
20
- t.datetime "created_at", null: false
21
- t.datetime "updated_at", null: false
19
+ t.bigint "record_id", null: false
20
+ t.datetime "created_at", precision: 6, null: false
21
+ t.datetime "updated_at", precision: 6, null: false
22
22
  t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true
23
23
  end
24
24
 
25
25
  create_table "active_storage_attachments", force: :cascade do |t|
26
26
  t.string "name", null: false
27
27
  t.string "record_type", null: false
28
- t.integer "record_id", null: false
29
- t.integer "blob_id", null: false
30
- t.datetime "created_at", null: false
28
+ t.bigint "record_id", null: false
29
+ t.bigint "blob_id", null: false
30
+ t.datetime "created_at", precision: 6, null: false
31
31
  t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
32
32
  t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
33
33
  end
@@ -37,20 +37,33 @@ ActiveRecord::Schema.define(version: 2019_01_26_192508) do
37
37
  t.string "filename", null: false
38
38
  t.string "content_type"
39
39
  t.text "metadata"
40
+ t.string "service_name", null: false
40
41
  t.bigint "byte_size", null: false
41
- t.string "checksum", null: false
42
- t.datetime "created_at", null: false
42
+ t.string "checksum"
43
+ t.datetime "created_at", precision: 6, null: false
43
44
  t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
44
45
  end
45
46
 
47
+ create_table "active_storage_variant_records", force: :cascade do |t|
48
+ t.bigint "blob_id", null: false
49
+ t.string "variation_digest", null: false
50
+ t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
51
+ end
52
+
46
53
  create_table "addresses", force: :cascade do |t|
47
54
  t.integer "user_id"
48
55
  t.string "street"
49
56
  t.string "city"
50
57
  t.string "state"
51
58
  t.string "zip_code"
52
- t.datetime "created_at", null: false
53
- t.datetime "updated_at", null: false
59
+ t.datetime "created_at", precision: 6, null: false
60
+ t.datetime "updated_at", precision: 6, null: false
61
+ end
62
+
63
+ create_table "bogons", force: :cascade do |t|
64
+ t.datetime "created_at", precision: 6, null: false
65
+ t.datetime "updated_at", precision: 6, null: false
66
+ t.integer "food_waste_main"
54
67
  end
55
68
 
56
69
  create_table "users", force: :cascade do |t|
@@ -62,8 +75,10 @@ ActiveRecord::Schema.define(version: 2019_01_26_192508) do
62
75
  t.text "preferences"
63
76
  t.boolean "terms", default: false
64
77
  t.string "type"
65
- t.datetime "created_at", null: false
66
- t.datetime "updated_at", null: false
78
+ t.datetime "created_at", precision: 6, null: false
79
+ t.datetime "updated_at", precision: 6, null: false
67
80
  end
68
81
 
82
+ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
83
+ add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
69
84
  end
data/demo/package.json CHANGED
@@ -2,16 +2,20 @@
2
2
  "name": "dummy",
3
3
  "private": true,
4
4
  "dependencies": {
5
- "@rails/actioncable": "^6.0.0-alpha",
6
- "@rails/actiontext": "^6.0.0-beta1",
7
- "@rails/activestorage": "^6.0.0-alpha",
8
- "@rails/ujs": "^6.0.0-alpha",
9
- "@rails/webpacker": "^4.0.0-rc.7",
5
+ "@rails/actioncable": "^6.1.0",
6
+ "@rails/actiontext": "^6.1.0",
7
+ "@rails/activestorage": "^6.1.0",
8
+ "@rails/ujs": "^6.1.0",
9
+ "@rails/webpacker": "^5.0.0",
10
10
  "trix": "^1.0.0",
11
11
  "turbolinks": "^5.2.0"
12
12
  },
13
13
  "version": "0.1.0",
14
14
  "devDependencies": {
15
- "webpack-dev-server": "^3.1.14"
15
+ "webpack-dev-server": "^4.0.0"
16
+ },
17
+ "scripts": {
18
+ "build": "webpack --config webpack.config.js",
19
+ "build:css": "webpack --config webpack.config.js"
16
20
  }
17
21
  }
@@ -0,0 +1,8 @@
1
+ require "test_helper"
2
+
3
+ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
4
+ include Capybara::Screenshot::Diff
5
+ driven_by :selenium, using: :headless_chrome, screen_size: [960, 720] do |capabilities|
6
+ capabilities.add_argument "force-device-scale-factor=1"
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require "test_helper"
2
+
3
+ class BootstrapControllerTest < ActionDispatch::IntegrationTest
4
+ test "should get form" do
5
+ get root_path
6
+ assert_response :success
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+
3
+ class UsersControllerTest < ActionDispatch::IntegrationTest
4
+ test "should post create" do
5
+ post users_url
6
+ assert_redirected_to root_path
7
+ end
8
+
9
+ test "should patch update" do
10
+ patch user_url(users(:one))
11
+ assert_redirected_to root_path
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ one:
2
+ email: one@test.com
@@ -0,0 +1,84 @@
1
+ require "application_system_test_case"
2
+
3
+ class BootstrapTest < ApplicationSystemTestCase
4
+ setup { screenshot_section :bootstrap }
5
+
6
+ test "visiting the index" do
7
+ screenshot_group :index
8
+ visit root_url
9
+
10
+ all(".toggle").each { |btn| execute_script "arguments[0].remove()", btn }
11
+
12
+ all("h3").each do |header|
13
+ example = header.first(:xpath, "./following-sibling::div")
14
+ scroll_to example
15
+ sleep 0.5
16
+ screenshot header.text.downcase.tr(" ", "_"), crop: bounds(example), color_distance_limit: 2
17
+ end
18
+ end
19
+
20
+ HEADERS = ["Generated HTML", "This generates", "Which outputs", "will be rendered as"].join("|").freeze
21
+ REGEXP =
22
+ /(?:!\[[^\]]*\]\([^)]+\)\s*)?```erb\n(.*?)\n```\s*((?:#{HEADERS}).*?$)?\s*(```html\n(?:.*?)\n```\s*)?/mi
23
+ .freeze
24
+ test "readme examples" do
25
+ screenshot_group :readme
26
+
27
+ readme = File.read(File.expand_path("../../../README.md", __dir__))
28
+ augmented_readme = readme.gsub(REGEXP) do |_|
29
+ erb = Regexp.last_match(1)
30
+ header = Regexp.last_match(2)
31
+ unless /\A<%= bootstrap[^>]*>\n\s*...\s*<% end %>\z/.match? erb
32
+ wrapped_erb = erb.starts_with?("<%= bootstrap") ? erb : <<~ERB
33
+ <%= bootstrap_form_with model: @user do |f| %>
34
+ #{erb}
35
+ <% end %>
36
+ ERB
37
+
38
+ visit fragment_path erb: wrapped_erb
39
+ wrapper = find(".p-3")
40
+ i = @screenshot_counter
41
+ screenshot :example, crop: bounds(wrapper)
42
+ wrapper = wrapper.find("form") if wrapped_erb != erb
43
+ html = wrapper["innerHTML"].strip.gsub("><", ">\n<")
44
+ assert html.present?, erb
45
+ doc = Nokogiri::HTML.fragment(html)
46
+ doc.traverse do |node|
47
+ if node.is_a?(Nokogiri::XML::Element)
48
+ node.attributes.sort_by(&:first).each do |name, value|
49
+ node.delete(name)
50
+ node[name] = value
51
+ end
52
+ end
53
+ end
54
+ html = doc.to_html
55
+ image = <<~MD
56
+ ![Example #{i}](demo/doc/screenshots/bootstrap/readme/#{format('%02i', i)}_example.png "Example #{i}")
57
+ MD
58
+ html = <<~MD
59
+
60
+ #{header || 'Generated HTML:'}
61
+
62
+ ```html
63
+ #{HtmlBeautifier.beautify(html)}
64
+ ```
65
+ MD
66
+ end
67
+ <<~MD
68
+ #{image}```erb
69
+ #{erb}
70
+ ```
71
+ #{html}
72
+ MD
73
+ end
74
+ augmented_readme.gsub!(/127.0.0.1:\d+/, "test.host")
75
+ File.write(File.expand_path("../../../README.md", __dir__), augmented_readme)
76
+ end
77
+
78
+ private
79
+
80
+ def bounds(node)
81
+ client_rect = evaluate_script("arguments[0].getBoundingClientRect()", node.native)
82
+ [client_rect["left"].floor, client_rect["top"].floor, client_rect["right"].ceil, client_rect["bottom"].ceil]
83
+ end
84
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV["RAILS_ENV"] = "test"
4
+
5
+ require_relative "../config/environment"
6
+ require "rails/test_help"
7
+
8
+ class ActiveSupport::TestCase
9
+ fixtures :all
10
+ end
@@ -0,0 +1,20 @@
1
+ const path = require("path")
2
+ const webpack = require("webpack")
3
+
4
+ module.exports = {
5
+ mode: "production",
6
+ devtool: "source-map",
7
+ entry: {
8
+ application: "./app/javascript/application.js"
9
+ },
10
+ output: {
11
+ filename: "[name].js",
12
+ sourceMapFilename: "[name].js.map",
13
+ path: path.resolve(__dirname, "app/assets/builds"),
14
+ },
15
+ plugins: [
16
+ new webpack.optimize.LimitChunkCountPlugin({
17
+ maxChunks: 1
18
+ })
19
+ ]
20
+ }