Skip to content

Commit 356edc7

Browse files
authored
Merge pull request rails#52752 from thejonroberts/devcontainer-generator-tests
Test DevcontainerGenerator
2 parents d8e8956 + 9fc7cbb commit 356edc7

File tree

4 files changed

+336
-7
lines changed

4 files changed

+336
-7
lines changed

railties/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ def create_devcontainer
3838

3939
def update_application_system_test_case
4040
return unless options[:system_test]
41-
return unless File.exist?("test/application_system_test_case.rb")
4241

43-
gsub_file("test/application_system_test_case.rb", /^\s*driven_by\b.*/, system_test_configuration)
42+
system_test_case_path = File.expand_path "test/application_system_test_case.rb", destination_root
43+
return unless File.exist? system_test_case_path
44+
45+
gsub_file(system_test_case_path, /^\s*driven_by\b.*/, system_test_configuration)
4446
end
4547

4648
def update_database_yml
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
5+
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
6+
driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ]
7+
end

railties/test/generators/devcontainer_generator_test.rb

Lines changed: 318 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,220 @@ module Generators
88
class DevcontainerGeneratorTest < Rails::Generators::TestCase
99
include GeneratorsTestHelper
1010

11-
def test_generates_devcontainer_files
11+
def test_creates_devcontainer_files
1212
run_generator
1313

1414
assert_file ".devcontainer/compose.yaml"
1515
assert_file ".devcontainer/Dockerfile"
1616
assert_file ".devcontainer/devcontainer.json"
17+
test_common_config
1718
end
1819

19-
def test_default_json_has_no_mounts
20+
def test_active_storage_option_default
2021
run_generator
2122

22-
assert_devcontainer_json_file do |devcontainer_config|
23-
assert_nil devcontainer_config["mounts"]
23+
assert_devcontainer_json_file do |devcontainer_json|
24+
assert_includes devcontainer_json["features"].keys, "ghcr.io/rails/devcontainer/features/activestorage"
25+
end
26+
end
27+
28+
def test_active_storage_option_skip
29+
run_generator [ "--skip-active-storage" ]
30+
31+
test_common_config
32+
assert_devcontainer_json_file do |devcontainer_json|
33+
assert_nil devcontainer_json["features"]["ghcr.io/rails/devcontainer/features/activestorage"]
34+
end
35+
end
36+
37+
def test_app_name_option_default
38+
run_generator
39+
40+
assert_devcontainer_json_file do |devcontainer_json|
41+
assert_equal "rails_app", devcontainer_json["name"]
42+
end
43+
44+
assert_compose_file do |compose|
45+
assert_equal "rails_app", compose["name"]
46+
end
47+
end
48+
49+
def test_app_name_option
50+
run_generator ["--app-name", "my-TestApp_name"]
51+
52+
test_common_config
53+
assert_devcontainer_json_file do |devcontainer_json|
54+
assert_equal "my-TestApp_name", devcontainer_json["name"]
55+
end
56+
57+
assert_compose_file do |compose|
58+
assert_equal "my-TestApp_name", compose["name"]
59+
end
60+
end
61+
62+
def test_database_default_sqlite3
63+
run_generator
64+
65+
assert_no_file "config/database.yml"
66+
assert_devcontainer_json_file do |devcontainer_json|
67+
assert_includes devcontainer_json["features"].keys, "ghcr.io/rails/devcontainer/features/sqlite3"
68+
end
69+
end
70+
71+
def test_database_mariadb_mysql
72+
run_generator [ "--database", "mariadb-mysql" ]
73+
74+
test_common_config
75+
assert_no_file "config/database.yml"
76+
assert_compose_file do |compose|
77+
expected_mariadb_config = {
78+
"image" => "mariadb:10.5",
79+
"restart" => "unless-stopped",
80+
"networks" => ["default"],
81+
"volumes" => ["mariadb-data:/var/lib/mysql"],
82+
"environment" => {
83+
"MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" => "true",
84+
},
85+
}
86+
assert_equal expected_mariadb_config, compose["services"]["mariadb"]
87+
assert_includes compose["volumes"].keys, "mariadb-data"
88+
assert_includes compose["services"]["rails-app"]["depends_on"], "mariadb"
89+
end
90+
91+
assert_devcontainer_json_file do |devcontainer_json|
92+
assert_equal "mariadb", devcontainer_json["containerEnv"]["DB_HOST"]
93+
assert_includes devcontainer_json["features"].keys, "ghcr.io/rails/devcontainer/features/mysql-client"
94+
assert_includes devcontainer_json["forwardPorts"], 3306
95+
end
96+
end
97+
98+
def test_database_mariadb_trilogy
99+
run_generator [ "--database", "mariadb-trilogy" ]
100+
101+
test_common_config
102+
assert_no_file "config/database.yml"
103+
assert_compose_file do |compose|
104+
expected_mariadb_config = {
105+
"image" => "mariadb:10.5",
106+
"restart" => "unless-stopped",
107+
"networks" => ["default"],
108+
"volumes" => ["mariadb-data:/var/lib/mysql"],
109+
"environment" => {
110+
"MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" => "true",
111+
},
112+
}
113+
assert_equal expected_mariadb_config, compose["services"]["mariadb"]
114+
assert_includes compose["volumes"].keys, "mariadb-data"
115+
assert_includes compose["services"]["rails-app"]["depends_on"], "mariadb"
116+
end
117+
118+
assert_devcontainer_json_file do |devcontainer_json|
119+
assert_equal "mariadb", devcontainer_json["containerEnv"]["DB_HOST"]
120+
assert_includes devcontainer_json["forwardPorts"], 3306
121+
end
122+
end
123+
124+
def test_database_mysql
125+
run_generator [ "--database", "mysql" ]
126+
127+
test_common_config
128+
assert_no_file "config/database.yml"
129+
assert_compose_file do |compose|
130+
expected_mysql_config = {
131+
"image" => "mysql/mysql-server:8.0",
132+
"restart" => "unless-stopped",
133+
"environment" => {
134+
"MYSQL_ALLOW_EMPTY_PASSWORD" => "true",
135+
"MYSQL_ROOT_HOST" => "%"
136+
},
137+
"volumes" => ["mysql-data:/var/lib/mysql"],
138+
"networks" => ["default"],
139+
}
140+
assert_equal expected_mysql_config, compose["services"]["mysql"]
141+
assert_includes compose["volumes"].keys, "mysql-data"
142+
assert_includes compose["services"]["rails-app"]["depends_on"], "mysql"
143+
end
144+
145+
assert_devcontainer_json_file do |devcontainer_json|
146+
assert_equal "mysql", devcontainer_json["containerEnv"]["DB_HOST"]
147+
assert_includes devcontainer_json["features"].keys, "ghcr.io/rails/devcontainer/features/mysql-client"
148+
assert_includes devcontainer_json["forwardPorts"], 3306
24149
end
25150
end
26151

27-
def test_dev_option_devcontainer_json_mounts_local_rails
152+
def test_database_postgresql
153+
run_generator [ "--database", "postgresql" ]
154+
155+
test_common_config
156+
157+
assert_file("config/database.yml") do |db_config|
158+
assert_match(/host: <%= ENV\["DB_HOST"\] %>/, db_config)
159+
assert_match(/username: postgres/, db_config)
160+
assert_match(/password: postgres/, db_config)
161+
end
162+
163+
assert_compose_file do |compose|
164+
expected_postgres_config = {
165+
"image" => "postgres:16.1",
166+
"restart" => "unless-stopped",
167+
"networks" => ["default"],
168+
"volumes" => ["postgres-data:/var/lib/postgresql/data"],
169+
"environment" => {
170+
"POSTGRES_USER" => "postgres",
171+
"POSTGRES_PASSWORD" => "postgres"
172+
}
173+
}
174+
assert_equal expected_postgres_config, compose["services"]["postgres"]
175+
assert_includes compose["volumes"].keys, "postgres-data"
176+
assert_includes compose["services"]["rails-app"]["depends_on"], "postgres"
177+
end
178+
179+
assert_devcontainer_json_file do |devcontainer_json|
180+
assert_equal "postgres", devcontainer_json["containerEnv"]["DB_HOST"]
181+
assert_includes devcontainer_json["features"].keys, "ghcr.io/rails/devcontainer/features/postgres-client"
182+
assert_includes devcontainer_json["forwardPorts"], 5432
183+
end
184+
end
185+
186+
def test_database_trilogy
187+
run_generator [ "--database", "trilogy" ]
188+
189+
test_common_config
190+
assert_no_file "config/database.yml"
191+
assert_compose_file do |compose|
192+
expected_mysql_config = {
193+
"image" => "mysql/mysql-server:8.0",
194+
"restart" => "unless-stopped",
195+
"environment" => {
196+
"MYSQL_ALLOW_EMPTY_PASSWORD" => "true",
197+
"MYSQL_ROOT_HOST" => "%"
198+
},
199+
"volumes" => ["mysql-data:/var/lib/mysql"],
200+
"networks" => ["default"],
201+
}
202+
assert_equal expected_mysql_config, compose["services"]["mysql"]
203+
assert_includes compose["volumes"].keys, "mysql-data"
204+
assert_includes compose["services"]["rails-app"]["depends_on"], "mysql"
205+
end
206+
207+
assert_devcontainer_json_file do |content|
208+
assert_equal "mysql", content["containerEnv"]["DB_HOST"]
209+
assert_includes content["forwardPorts"], 3306
210+
end
211+
end
212+
213+
def test_dev_option_default
214+
run_generator
215+
216+
assert_devcontainer_json_file do |devcontainer_json|
217+
assert_nil devcontainer_json["mounts"]
218+
end
219+
end
220+
221+
def test_dev_option
28222
run_generator ["--dev"]
29223

224+
test_common_config
30225
assert_devcontainer_json_file do |devcontainer_json|
31226
mounts = devcontainer_json["mounts"].sole
32227

@@ -35,6 +230,124 @@ def test_dev_option_devcontainer_json_mounts_local_rails
35230
assert_equal Rails::Generators::RAILS_DEV_PATH, mounts["target"]
36231
end
37232
end
233+
234+
def test_node_option_default
235+
run_generator
236+
237+
assert_devcontainer_json_file do |devcontainer_json|
238+
assert_not_includes devcontainer_json["features"].keys, "ghcr.io/devcontainers/features/node:1"
239+
end
240+
end
241+
242+
def test_node_option
243+
run_generator ["--node"]
244+
245+
test_common_config
246+
assert_devcontainer_json_file do |devcontainer_json|
247+
assert_includes devcontainer_json["features"].keys, "ghcr.io/devcontainers/features/node:1"
248+
end
249+
end
250+
251+
def test_redis_option_default
252+
run_generator
253+
254+
assert_compose_file do |compose|
255+
assert_includes compose["services"]["rails-app"]["depends_on"], "redis"
256+
expected_redis_config = {
257+
"image" => "redis:7.2",
258+
"restart" => "unless-stopped",
259+
"volumes" => ["redis-data:/data"]
260+
}
261+
assert_equal expected_redis_config, compose["services"]["redis"]
262+
assert_equal ["redis-data"], compose["volumes"].keys
263+
end
264+
265+
assert_devcontainer_json_file do |devcontainer_json|
266+
assert_equal "redis://redis:6379/1", devcontainer_json["containerEnv"]["REDIS_URL"]
267+
assert_includes devcontainer_json["forwardPorts"], 6379
268+
end
269+
end
270+
271+
def test_redis_option_skip
272+
run_generator ["--skip-redis"]
273+
274+
test_common_config
275+
assert_compose_file do |compose|
276+
assert_not_includes compose["services"]["rails-app"]["depends_on"], "redis"
277+
assert_nil compose["services"]["redis"]
278+
assert_nil compose["volumes"]
279+
end
280+
281+
assert_devcontainer_json_file do |devcontainer_json|
282+
assert_not_includes devcontainer_json["forwardPorts"], 6379
283+
end
284+
end
285+
286+
def test_system_test_option_default
287+
copy_application_system_test_case
288+
289+
run_generator
290+
291+
assert_devcontainer_json_file do |devcontainer_json|
292+
assert_equal "45678", devcontainer_json["containerEnv"]["CAPYBARA_SERVER_PORT"]
293+
assert_equal "selenium", devcontainer_json["containerEnv"]["SELENIUM_HOST"]
294+
end
295+
296+
assert_file("test/application_system_test_case.rb") do |system_test_case|
297+
assert_match(/^ if ENV\["CAPYBARA_SERVER_PORT"\]/, system_test_case)
298+
assert_match(/^ served_by host: "rails-app", port: ENV\["CAPYBARA_SERVER_PORT"\]/, system_test_case)
299+
assert_match(/^ driven_by :selenium, using: :headless_chrome, screen_size: \[ 1400, 1400 \], options: {$/, system_test_case)
300+
assert_match(/^ browser: :remote,$/, system_test_case)
301+
assert_match(/^ url: "http:\/\/\#{ENV\["SELENIUM_HOST"\]}:4444"$/, system_test_case)
302+
end
303+
end
304+
305+
def test_system_test_option_does_not_create_new_file
306+
run_generator ["--system-test"]
307+
308+
test_common_config
309+
assert_no_file "test/application_system_test_case.rb"
310+
end
311+
312+
def test_system_test_option_skip
313+
copy_application_system_test_case
314+
315+
run_generator [ "--skip-system-test", "--force" ]
316+
317+
test_common_config
318+
assert_compose_file do |compose|
319+
assert_not_includes compose["services"]["rails-app"]["depends_on"], "selenium"
320+
assert_not_includes compose["services"].keys, "selenium"
321+
end
322+
assert_devcontainer_json_file do |devcontainer_json|
323+
assert_nil devcontainer_json["containerEnv"]["CAPYBARA_SERVER_PORT"]
324+
end
325+
end
326+
327+
private
328+
def test_common_config
329+
assert_file(".devcontainer/Dockerfile") do |dockerfile|
330+
assert_match(/ARG RUBY_VERSION=#{RUBY_VERSION}/, dockerfile)
331+
end
332+
333+
assert_devcontainer_json_file do |devcontainer_json|
334+
assert_includes devcontainer_json["features"].keys, "ghcr.io/devcontainers/features/github-cli:1"
335+
assert_includes devcontainer_json["forwardPorts"], 3000
336+
end
337+
338+
assert_compose_file do |compose|
339+
expected_app_config = {
340+
"build" => {
341+
"context" => "..",
342+
"dockerfile" => ".devcontainer/Dockerfile"
343+
},
344+
"volumes" => ["../..:/workspaces:cached"],
345+
"command" => "sleep infinity"
346+
}
347+
actual_independent_config = compose["services"]["rails-app"].except("depends_on")
348+
assert_equal expected_app_config, actual_independent_config
349+
end
350+
end
38351
end
39352
end
40353
end

railties/test/generators/generators_test_helper.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ def copy_gemfile(*gemfile_entries)
7878
File.write File.join(destination, "Gemfile"), gemfile
7979
end
8080

81+
def copy_application_system_test_case
82+
content = File.read(File.expand_path("../fixtures/test/application_system_test_case.rb", __dir__))
83+
destination = File.join(destination_root, "test")
84+
mkdir_p(destination)
85+
File.write File.join(destination, "application_system_test_case.rb"), content
86+
end
87+
8188
def copy_dockerfile
8289
dockerfile = File.expand_path("../fixtures/Dockerfile.test", __dir__)
8390
dockerfile = evaluate_template_docker(dockerfile)

0 commit comments

Comments
 (0)