diff --git a/AGENTS.md b/AGENTS.md index 97e56f7..fa79149 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,8 +13,8 @@ There are 2 separate sets of models using authentication: - Students (non-traditional Magic Links) used for Students to access their specific content ## Skills - -- Look in the [Skills](./skills) Folder for relevant skills +- [rails-test-fixtures-conventions](./skills/rails-test-fixtures-conventions.md) +- [erb-templates-conventions](./skills/erb-templates-conventions.md) ## Conventions diff --git a/skills/Writing ERB Templates.md b/skills/erb-templates-conventions.md similarity index 100% rename from skills/Writing ERB Templates.md rename to skills/erb-templates-conventions.md diff --git a/skills/rails-test-fixtures-conventions.md b/skills/rails-test-fixtures-conventions.md new file mode 100644 index 0000000..e2d874f --- /dev/null +++ b/skills/rails-test-fixtures-conventions.md @@ -0,0 +1,24 @@ +# Rails Test Fixtures + +Goal: keep fixtures few. Too many fixtures = nobody understands the dependency graph. + +## Rules + +1. **1-2 fixtures per model max** + - Name them `:one` and `:two` + - Plain, valid, boring attributes + - Minimal dependencies + - Add `:two` only to compare two records + +2. **Customize in the test, not the fixture** + - `developers(:one).update!(field: value)` + - Only set the field the test cares about + - Extra DB write is fine, readability wins + +3. **Use a custom helper method for when needed** + - Create a method like `create_thing` that allows customizing attributes + +4. **New named fixture = last resort** + - Only for deep/complex required associations + - Give it a real name, not `:three` (e.g. `:paying_customer`) + - Max 1-2 per model \ No newline at end of file diff --git a/test/controllers/classroom_modules_controller_test.rb b/test/controllers/classroom_modules_controller_test.rb index c03e2d3..7816c18 100644 --- a/test/controllers/classroom_modules_controller_test.rb +++ b/test/controllers/classroom_modules_controller_test.rb @@ -3,7 +3,7 @@ class ClassroomModulesControllerTest < ActionDispatch::IntegrationTest setup do @classroom_module = classroom_modules(:one) - sign_in_as users(:admin) + sign_in_as users(:one) end test "update sets publish_on and responds with turbo stream" do diff --git a/test/controllers/classrooms_controller_test.rb b/test/controllers/classrooms_controller_test.rb index ae316c5..4542666 100644 --- a/test/controllers/classrooms_controller_test.rb +++ b/test/controllers/classrooms_controller_test.rb @@ -3,7 +3,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest setup do @classroom = classrooms(:one) - sign_in_as users(:admin) + sign_in_as users(:one) end test "should get edit" do @@ -27,7 +27,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest end test "should add a program enrollment" do - program = programs(:"3dw") + program = programs(:two) assert_difference "ClassroomProgram.count" do patch classroom_url(@classroom), params: { @@ -59,7 +59,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest test "should remove an enrollment" do enrollment = classroom_programs(:one) - @classroom.classroom_programs.create!(program: programs(:"3dw"), level: "basic") + @classroom.classroom_programs.create!(program: programs(:two), level: "basic") assert_difference "ClassroomProgram.count", -1 do patch classroom_url(@classroom), params: { @@ -89,7 +89,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest end test "is invalid when a program is selected without a level" do - program = programs(:"3dw") + program = programs(:two) assert_no_difference "ClassroomProgram.count" do patch classroom_url(@classroom), params: { @@ -104,7 +104,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest end test "generates modules when a new enrollment is added" do - program = programs(:"3dw") + program = programs(:two) assert_difference "ClassroomModule.count" do patch classroom_url(@classroom), params: { @@ -116,7 +116,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest end cp = @classroom.classroom_programs.find_by!(program: program) - assert cp.classroom_modules.exists?(content_module: content_modules(:moderate_wellness)) + assert cp.classroom_modules.exists?(content_module: content_modules(:two)) end test "is invalid when changing a level that has scheduled modules" do @@ -159,7 +159,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest test "should create classroom" do school = schools(:one) - program = programs(:kyh) + program = programs(:one) teacher = Teacher.create!(name: "Teacher 3", school: school) assert_difference "Classroom.count" do @@ -185,7 +185,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest post school_classrooms_url(school), params: { classroom: { name: "Classroom 4", - classroom_programs_attributes: [ { program_id: programs(:kyh).id, level: "basic" } ] + classroom_programs_attributes: [ { program_id: programs(:one).id, level: "basic" } ] } } @@ -201,7 +201,7 @@ class ClassroomsControllerTest < ActionDispatch::IntegrationTest post school_classrooms_url(school), params: { classroom: { name: "Classroom 5", - classroom_programs_attributes: [ { program_id: programs(:kyh).id, level: "basic" } ] + classroom_programs_attributes: [ { program_id: programs(:one).id, level: "basic" } ] } } end diff --git a/test/controllers/content_modules_controller_test.rb b/test/controllers/content_modules_controller_test.rb index d50d3dd..082568b 100644 --- a/test/controllers/content_modules_controller_test.rb +++ b/test/controllers/content_modules_controller_test.rb @@ -2,8 +2,8 @@ class ContentModulesControllerTest < ActionDispatch::IntegrationTest setup do - @content_module = content_modules(:intro) - sign_in_as users(:admin) + @content_module = content_modules(:one) + sign_in_as users(:one) end test "should get index" do @@ -12,7 +12,7 @@ class ContentModulesControllerTest < ActionDispatch::IntegrationTest end test "index marks the active program tab as selected" do - program = programs(:kyh) + program = programs(:one) get content_modules_url(program_id: program.id) assert_select "a[role='tab'][aria-selected='true'][href*='program_id=#{program.id}']" end @@ -25,7 +25,7 @@ class ContentModulesControllerTest < ActionDispatch::IntegrationTest test "should create content module" do assert_difference "ContentModule.count" do post content_modules_url, params: { - content_module: { name: "New Module", program_id: programs(:kyh).id, level: "moderate", position: 1 } + content_module: { name: "New Module", program_id: programs(:one).id, level: "moderate", position: 1 } } end assert_redirected_to content_modules_url @@ -34,7 +34,7 @@ class ContentModulesControllerTest < ActionDispatch::IntegrationTest test "should not create with missing name" do assert_no_difference "ContentModule.count" do post content_modules_url, params: { - content_module: { name: "", program_id: programs(:kyh).id, level: "basic" } + content_module: { name: "", program_id: programs(:one).id, level: "basic" } } end assert_response :unprocessable_entity @@ -65,7 +65,7 @@ class ContentModulesControllerTest < ActionDispatch::IntegrationTest end test "should destroy content module" do - content_module = ContentModule.create!(program: programs(:kyh), level: "basic", name: "To Delete") + content_module = ContentModule.create!(program: programs(:one), level: "basic", name: "To Delete") assert_difference "ContentModule.count", -1 do delete content_module_url(content_module) end diff --git a/test/controllers/games_controller_test.rb b/test/controllers/games_controller_test.rb index cbd104a..7a21966 100644 --- a/test/controllers/games_controller_test.rb +++ b/test/controllers/games_controller_test.rb @@ -3,8 +3,8 @@ class GamesControllerTest < ActionDispatch::IntegrationTest setup do @game = games(:one) - @content_module = content_modules(:intro) - sign_in_as users(:admin) + @content_module = content_modules(:one) + sign_in_as users(:one) end test "should get index" do diff --git a/test/controllers/links_controller_test.rb b/test/controllers/links_controller_test.rb index 78dc4fe..3782809 100644 --- a/test/controllers/links_controller_test.rb +++ b/test/controllers/links_controller_test.rb @@ -2,9 +2,9 @@ class LinksControllerTest < ActionDispatch::IntegrationTest setup do - @link = links(:survey_one) - @mod = content_modules(:intro) - sign_in_as users(:admin) + @link = links(:one) + @mod = content_modules(:one) + sign_in_as users(:one) end test "should get new" do diff --git a/test/controllers/schools_controller_test.rb b/test/controllers/schools_controller_test.rb index 10e5d1c..3c0eabf 100644 --- a/test/controllers/schools_controller_test.rb +++ b/test/controllers/schools_controller_test.rb @@ -3,7 +3,7 @@ class SchoolsControllerTest < ActionDispatch::IntegrationTest setup do @school = schools(:one) - sign_in_as users(:admin) + sign_in_as users(:one) end test "should get index" do diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index a393273..7ac3664 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -1,7 +1,7 @@ require "test_helper" class SessionsControllerTest < ActionDispatch::IntegrationTest - setup { @user = users(:admin) } + setup { @user = users(:one) } test "new" do get new_session_path diff --git a/test/controllers/student_home_controller_test.rb b/test/controllers/student_home_controller_test.rb index 1cdaa5c..b681203 100644 --- a/test/controllers/student_home_controller_test.rb +++ b/test/controllers/student_home_controller_test.rb @@ -2,7 +2,7 @@ class StudentHomeControllerTest < ActionDispatch::IntegrationTest test "should get index" do - student_sign_in_as(students(:ada)) + student_sign_in_as(students(:one)) get student_homes_path assert_response :success diff --git a/test/controllers/student_homes_controller_test.rb b/test/controllers/student_homes_controller_test.rb index 32e6aa1..d7567a2 100644 --- a/test/controllers/student_homes_controller_test.rb +++ b/test/controllers/student_homes_controller_test.rb @@ -2,7 +2,7 @@ class StudentHomesControllerTest < ActionDispatch::IntegrationTest setup do - @student = students(:ada) + @student = students(:one) student_sign_in_as @student end @@ -21,14 +21,14 @@ class StudentHomesControllerTest < ActionDispatch::IntegrationTest test "shows links inside published modules" do get student_homes_url assert_response :success - link = content_modules(:intro).links.first + link = content_modules(:one).links.first assert_select "a[target='_blank']", text: /#{link.title}/ if link end test "most recently published module has the open attribute" do # Add a second published module so there's a distinct "most recent" second_module = ContentModule.create!( - program: programs(:kyh), level: "basic", name: "Second Module", position: 2 + program: programs(:one), level: "basic", name: "Second Module", position: 2 ) classroom_programs(:one).classroom_modules.create!( content_module: second_module, publish_on: Date.current @@ -40,7 +40,7 @@ class StudentHomesControllerTest < ActionDispatch::IntegrationTest test "all modules published on the same latest date have the open attribute" do second_module = ContentModule.create!( - program: programs(:kyh), level: "basic", name: "Second Module", position: 2 + program: programs(:one), level: "basic", name: "Second Module", position: 2 ) classroom_modules(:one).update!(publish_on: Date.current) classroom_programs(:one).classroom_modules.create!( @@ -64,7 +64,7 @@ class StudentHomesControllerTest < ActionDispatch::IntegrationTest test "shows tab bar when classroom has multiple program enrollments" do classroom_programs(:one).classroom.classroom_programs.create!( - program: programs(:"3dw"), level: "moderate" + program: programs(:two), level: "moderate" ) get student_homes_url @@ -74,7 +74,7 @@ class StudentHomesControllerTest < ActionDispatch::IntegrationTest test "tab switching shows the selected program as active" do enrollment = classroom_programs(:one) - enrollment.classroom.classroom_programs.create!(program: programs(:"3dw"), level: "moderate") + enrollment.classroom.classroom_programs.create!(program: programs(:two), level: "moderate") get student_homes_url(classroom_program_id: enrollment.id) assert_select "a[role='tab'][aria-selected='true'][href*='classroom_program_id=#{enrollment.id}']" diff --git a/test/controllers/student_sessions_controller_test.rb b/test/controllers/student_sessions_controller_test.rb index 1c63c2c..9f1a92f 100644 --- a/test/controllers/student_sessions_controller_test.rb +++ b/test/controllers/student_sessions_controller_test.rb @@ -1,7 +1,7 @@ require "test_helper" class StudentSessionsControllerTest < ActionDispatch::IntegrationTest - setup { @student = students(:ada) } + setup { @student = students(:one) } test "new" do get new_student_session_path diff --git a/test/controllers/students_controller_test.rb b/test/controllers/students_controller_test.rb index f34d3d1..0460aae 100644 --- a/test/controllers/students_controller_test.rb +++ b/test/controllers/students_controller_test.rb @@ -3,8 +3,8 @@ class StudentsControllerTest < ActionDispatch::IntegrationTest setup do @school = schools(:one) - @student = students(:ada) - sign_in_as users(:admin) + @student = students(:one) + sign_in_as users(:one) end test "should get index" do diff --git a/test/controllers/teachers_controller_test.rb b/test/controllers/teachers_controller_test.rb index d73a328..bb7ddde 100644 --- a/test/controllers/teachers_controller_test.rb +++ b/test/controllers/teachers_controller_test.rb @@ -3,7 +3,7 @@ class TeachersControllerTest < ActionDispatch::IntegrationTest setup do @school = schools(:one) - sign_in_as users(:admin) + sign_in_as users(:one) end test "should get index" do diff --git a/test/fixtures/classroom_modules.yml b/test/fixtures/classroom_modules.yml index 93021f0..02ff168 100644 --- a/test/fixtures/classroom_modules.yml +++ b/test/fixtures/classroom_modules.yml @@ -1,9 +1,4 @@ one: classroom_program: one - content_module: intro - publish_on: 2026-05-01 - -scheduled: - classroom_program: two - content_module: moderate_wellness + content_module: one publish_on: 2026-05-01 diff --git a/test/fixtures/classroom_programs.yml b/test/fixtures/classroom_programs.yml index cad6043..c7e3bd1 100644 --- a/test/fixtures/classroom_programs.yml +++ b/test/fixtures/classroom_programs.yml @@ -1,9 +1,9 @@ one: classroom: one - program: kyh + program: one level: basic two: classroom: two - program: 3dw + program: two level: moderate diff --git a/test/fixtures/content_modules.yml b/test/fixtures/content_modules.yml index 9093b5c..808a0b1 100644 --- a/test/fixtures/content_modules.yml +++ b/test/fixtures/content_modules.yml @@ -1,17 +1,11 @@ -intro: - program: kyh +one: + program: one level: basic name: Introduction to Health position: 1 -moderate_wellness: - program: 3dw +two: + program: two level: moderate name: Moderate Wellness position: 1 - -advanced_wellness: - program: 3dw - level: advanced - name: Advanced Wellness - position: 1 diff --git a/test/fixtures/game_attempts.yml b/test/fixtures/game_attempts.yml index 52fd071..8db4e1f 100644 --- a/test/fixtures/game_attempts.yml +++ b/test/fixtures/game_attempts.yml @@ -5,7 +5,7 @@ one: outcome: completed started_at: 2026-08-29 11:53:38 finished_at: 2026-08-29 11:53:38 - student: ada + student: one game: one token: onetoken @@ -14,6 +14,6 @@ two: outcome: expired started_at: 2026-08-29 11:53:38 finished_at: 2026-08-29 11:53:38 - student: grace + student: two game: two token: twotoken diff --git a/test/fixtures/games.yml b/test/fixtures/games.yml index 39b1211..bd0ba0c 100644 --- a/test/fixtures/games.yml +++ b/test/fixtures/games.yml @@ -3,11 +3,11 @@ one: title: Game 1 slug: game-1 - content_module: intro + content_module: one description: MyText two: title: Game 2 slug: game-2 - content_module: moderate_wellness + content_module: one description: MyText diff --git a/test/fixtures/links.yml b/test/fixtures/links.yml index 49fd9ba..c6fce72 100644 --- a/test/fixtures/links.yml +++ b/test/fixtures/links.yml @@ -1,13 +1,6 @@ -survey_one: - content_module: intro +one: + content_module: one title: Health Survey url: https://example.com/survey/1 link_type: survey position: 1 - -survey_two: - content_module: intro - title: Health Survey 2 - url: https://example.com/survey/2 - link_type: survey - position: 2 diff --git a/test/fixtures/programs.yml b/test/fixtures/programs.yml index f5b4264..705afe6 100644 --- a/test/fixtures/programs.yml +++ b/test/fixtures/programs.yml @@ -1,7 +1,7 @@ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html -kyh: +one: name: Know Your Health -3dw: +two: name: 3D Wellness diff --git a/test/fixtures/students.yml b/test/fixtures/students.yml index ee5c1f5..b8cdd1d 100644 --- a/test/fixtures/students.yml +++ b/test/fixtures/students.yml @@ -1,4 +1,4 @@ -ada: +one: first_name: Ada last_name: Lovelace email: @@ -7,7 +7,7 @@ ada: school: one classroom: one -grace: +two: first_name: Grace last_name: Hopper email: ghopper@example.com diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 53e7732..cd15951 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -1,6 +1,6 @@ <% password_digest = BCrypt::Password.create("password") %> -admin: - name: Admin User - email_address: admin@example.com +one: + name: User 1 + email_address: user1@example.com password_digest: <%= password_digest %> diff --git a/test/models/classroom_test.rb b/test/models/classroom_test.rb index 3405fe9..5191bd8 100644 --- a/test/models/classroom_test.rb +++ b/test/models/classroom_test.rb @@ -3,7 +3,7 @@ class ClassroomTest < ActiveSupport::TestCase test "creates enrollment via nested attributes" do classroom = classrooms(:one) - program = programs(:"3dw") + program = programs(:two) assert_difference "ClassroomProgram.count" do classroom.update!( @@ -31,7 +31,7 @@ class ClassroomTest < ActiveSupport::TestCase enrollment = classroom_programs(:one) # Add a second enrollment first so the classroom still has one after destruction - classroom.classroom_programs.create!(program: programs(:"3dw"), level: "basic") + classroom.classroom_programs.create!(program: programs(:two), level: "basic") assert_difference "ClassroomProgram.count", -1 do classroom.update!( @@ -42,7 +42,7 @@ class ClassroomTest < ActiveSupport::TestCase test "rejects new enrollment when checkbox is unchecked (_destroy: 1)" do classroom = classrooms(:one) - program = programs(:"3dw") + program = programs(:two) assert_no_difference "ClassroomProgram.count" do classroom.update!( @@ -53,7 +53,7 @@ class ClassroomTest < ActiveSupport::TestCase test "is invalid when a new enrollment has no level selected" do classroom = classrooms(:one) - program = programs(:"3dw") + program = programs(:two) classroom.assign_attributes( classroom_programs_attributes: [ { program_id: program.id, level: "" } ] diff --git a/test/models/content_module_test.rb b/test/models/content_module_test.rb index 95a4039..255b98c 100644 --- a/test/models/content_module_test.rb +++ b/test/models/content_module_test.rb @@ -2,7 +2,7 @@ class ContentModuleTest < ActiveSupport::TestCase setup do - @program = programs(:kyh) + @program = programs(:one) end test "is valid with required fields" do diff --git a/test/models/game_attempt_test.rb b/test/models/game_attempt_test.rb index 47024b5..9d6362e 100644 --- a/test/models/game_attempt_test.rb +++ b/test/models/game_attempt_test.rb @@ -2,7 +2,7 @@ class GameAttemptTest < ActiveSupport::TestCase test "can start a game attempt" do - attempt = GameAttempt.create(student: students(:ada), game: games(:one)) + attempt = GameAttempt.create(student: students(:one), game: games(:one)) refute attempt.started? @@ -12,7 +12,7 @@ class GameAttemptTest < ActiveSupport::TestCase end test "can complete a game attempt" do - attempt = GameAttempt.create(student: students(:ada), game: games(:one)) + attempt = GameAttempt.create(student: students(:one), game: games(:one)) attempt.start! refute attempt.finished? @@ -23,7 +23,7 @@ class GameAttemptTest < ActiveSupport::TestCase end test "new game attempts have a token" do - attempt = GameAttempt.create(student: students(:ada), game: games(:one)) + attempt = GameAttempt.create(student: students(:one), game: games(:one)) assert attempt.token.present? end end diff --git a/test/models/game_test.rb b/test/models/game_test.rb index 4e088b7..3622a6f 100644 --- a/test/models/game_test.rb +++ b/test/models/game_test.rb @@ -12,14 +12,14 @@ class GameTest < ActiveSupport::TestCase end test "should not save game with duplicate title" do - content_module = ContentModule.create!(program: programs(:kyh), level: "basic", name: "Test Module") + content_module = ContentModule.create!(program: programs(:one), level: "basic", name: "Test Module") Game.create!(title: "Test Game", slug: "test-slug", content_module: content_module) duplicate_game = Game.new(title: "Test Game", slug: "another-slug", content_module: content_module) assert_not duplicate_game.save, "Saved the game with a duplicate title" end test "should not save game with duplicate slug" do - content_module = ContentModule.create!(program: programs(:kyh), level: "basic", name: "Test Module") + content_module = ContentModule.create!(program: programs(:one), level: "basic", name: "Test Module") Game.create!(title: "Test Game", slug: "test-slug", content_module: content_module) duplicate_game = Game.new(title: "Another Game", slug: "test-slug", content_module: content_module) assert_not duplicate_game.save, "Saved the game with a duplicate slug" diff --git a/test/models/link_test.rb b/test/models/link_test.rb index ec5e4b9..c1889be 100644 --- a/test/models/link_test.rb +++ b/test/models/link_test.rb @@ -2,24 +2,24 @@ class LinkTest < ActiveSupport::TestCase test "is valid with required fields" do - link = Link.new(content_module: content_modules(:intro), title: "My Link", url: "https://example.com", link_type: "survey") + link = Link.new(content_module: content_modules(:one), title: "My Link", url: "https://example.com", link_type: "survey") assert link.valid? end test "is invalid without a title" do - link = Link.new(content_module: content_modules(:intro), url: "https://example.com", link_type: "survey") + link = Link.new(content_module: content_modules(:one), url: "https://example.com", link_type: "survey") assert_not link.valid? assert_includes link.errors[:title], "can't be blank" end test "is invalid without a url" do - link = Link.new(content_module: content_modules(:intro), title: "My Link", link_type: "survey") + link = Link.new(content_module: content_modules(:one), title: "My Link", link_type: "survey") assert_not link.valid? assert_includes link.errors[:url], "can't be blank" end test "is invalid without a link_type" do - link = Link.new(content_module: content_modules(:intro), title: "My Link", url: "https://example.com") + link = Link.new(content_module: content_modules(:one), title: "My Link", url: "https://example.com") assert_not link.valid? end end diff --git a/test/system/student_accessibility_test.rb b/test/system/student_accessibility_test.rb index 2ce2292..dc76895 100644 --- a/test/system/student_accessibility_test.rb +++ b/test/system/student_accessibility_test.rb @@ -2,7 +2,7 @@ class StudentAccessibilityTest < ApplicationSystemTestCase test "student can login from classroom roster and home page is accessible" do - student = students(:ada) + student = students(:one) classroom = classrooms(:one) # Visit classroom roster