@@ -116,6 +116,19 @@ def mock_failing_update(error_messages = ["Update error"])
116116 end
117117 end
118118
119+ describe "assessments disabled" do
120+ before do
121+ allow ( ENV ) . to receive ( :[] ) . and_call_original
122+ allow ( ENV ) . to receive ( :[] ) . with ( "HAS_ASSESSMENTS" ) . and_return ( "false" )
123+ login_as ( user )
124+ end
125+
126+ it "returns 404 when assessments are disabled" do
127+ get "/inspections"
128+ expect ( response ) . to have_http_status ( :not_found )
129+ end
130+ end
131+
119132 describe "when logged in" do
120133 before { login_as ( user ) }
121134
@@ -166,6 +179,22 @@ def mock_failing_update(error_messages = ["Update error"])
166179 # Verify that the Rails path helper generates the expected URL
167180 expect ( inspection_path ( inspection , format : :pdf ) ) . to eq ( "/inspections/#{ inspection . id } .pdf" )
168181 end
182+
183+ context "JSON format" do
184+ it "returns inspection data as JSON using InspectionBlueprint" do
185+ # Don't mock - let InspectionBlueprint actually render
186+ get "/inspections/#{ inspection . id } .json"
187+
188+ expect ( response ) . to have_http_status ( :success )
189+ expect ( response . content_type ) . to include ( "application/json" )
190+
191+ json = JSON . parse ( response . body )
192+ # id is excluded from public API, check other fields
193+ expect ( json [ "inspection_date" ] ) . to be_present
194+ expect ( json [ "complete" ] ) . to be false
195+ expect ( json [ "passed" ] ) . to eq ( inspection . passed )
196+ end
197+ end
169198 end
170199
171200 describe "POST /create" do
@@ -273,6 +302,29 @@ def mock_failing_update(error_messages = ["Update error"])
273302 expect ( flash [ :alert ] ) . to match ( /invalid.*unit/i )
274303 end
275304
305+ context "with image processing error" do
306+ before do
307+ # Simulate image processing error by stubbing process_image_params
308+ allow_any_instance_of ( InspectionsController ) . to receive ( :process_image_params ) do |controller , params , *args |
309+ controller . instance_variable_set ( :@image_processing_error , StandardError . new ( "Image processing failed" ) )
310+ params
311+ end
312+ end
313+
314+ it "handles image processing errors gracefully" do
315+ patch "/inspections/#{ inspection . id } " , params : {
316+ inspection : {
317+ risk_assessment : "Test assessment" ,
318+ photo_1 : fixture_file_upload ( "spec/fixtures/files/test_image.jpg" , "image/jpeg" )
319+ }
320+ }
321+
322+ expect ( response ) . to have_http_status ( :unprocessable_content )
323+ expect ( flash [ :alert ] ) . to eq ( "Image processing failed" )
324+ expect ( response ) . to render_template ( :edit )
325+ end
326+ end
327+
276328 %w[ json turbo_stream ] . each do |format |
277329 context "#{ format } format" do
278330 let ( :headers ) do
@@ -361,12 +413,18 @@ def mock_failing_update(error_messages = ["Update error"])
361413
362414 inspection . reload
363415 expect ( inspection . unit ) . to eq ( unit1 )
416+
417+ # Verify event logging
418+ event = Event . for_resource ( inspection ) . last
419+ expect ( event . action ) . to eq ( "unit_changed" )
420+ expect ( event . details ) . to include ( unit1 . name )
364421 end
365422
366423 it "handles invalid unit_id" do
367424 patch "/inspections/#{ inspection . id } /update_unit" , params : { unit_id : "invalid" }
368425 expect_redirect_with_alert ( select_unit_inspection_path ( inspection ) , /invalid.*unit/i )
369426 end
427+
370428 end
371429 end
372430
@@ -434,6 +492,240 @@ def mock_failing_update(error_messages = ["Update error"])
434492 expect ( response ) . to have_http_status ( :success )
435493 end
436494 end
495+
496+ describe "HEAD requests" do
497+ let ( :inspection ) { create ( :inspection , user : user , unit : unit ) }
498+
499+ it "returns 200 OK for HEAD request" do
500+ head "/inspections/#{ inspection . id } "
501+ expect ( response ) . to have_http_status ( :ok )
502+ expect ( response . body ) . to be_empty
503+ end
504+ end
505+
506+ describe "GET /log" do
507+ let ( :inspection ) { create ( :inspection , user : user , unit : unit ) }
508+
509+ before do
510+ # Create some events for the inspection
511+ Event . log (
512+ user : user ,
513+ action : "created" ,
514+ resource : inspection ,
515+ details : "Inspection created"
516+ )
517+ Event . log (
518+ user : user ,
519+ action : "updated" ,
520+ resource : inspection ,
521+ details : "Inspection updated"
522+ )
523+ end
524+
525+ it "displays inspection event log" do
526+ get "/inspections/#{ inspection . id } /log"
527+
528+ expect ( response ) . to have_http_status ( :success )
529+ expect ( assigns ( :events ) ) . to be_present
530+ expect ( assigns ( :events ) . count ) . to eq ( 2 )
531+ expect ( assigns ( :title ) ) . to include ( inspection . id )
532+ end
533+ end
534+
535+
536+ describe "prefill functionality" do
537+ let ( :previous_inspection ) do
538+ create ( :inspection , :completed ,
539+ user : user ,
540+ unit : unit ,
541+ risk_assessment : "Previous risk" )
542+ end
543+
544+ let ( :new_inspection ) do
545+ create ( :inspection , user : user , unit : unit )
546+ end
547+
548+ before do
549+ # Set up previous inspection on unit
550+ allow_any_instance_of ( Unit ) . to receive ( :last_inspection ) . and_return ( previous_inspection )
551+ end
552+
553+ describe "translate_field_name" do
554+ it "translates field names for prefill display" do
555+ get "/inspections/#{ new_inspection . id } /edit" , params : { tab : "inspection" }
556+
557+ expect ( response ) . to have_http_status ( :success )
558+ # The prefilled_fields will be set if there are fields to prefill
559+ expect ( assigns ( :prefilled_fields ) ) . to be_an ( Array )
560+ end
561+
562+ it "handles pass/fail field translation for assessments" do
563+ # Update previous inspection's assessment with data
564+ previous_inspection . user_height_assessment . update (
565+ containing_wall_height : 100 ,
566+ containing_wall_height_comment : "Test comment"
567+ )
568+
569+ get "/inspections/#{ new_inspection . id } /edit" , params : { tab : "user_height" }
570+
571+ expect ( response ) . to have_http_status ( :success )
572+ expect ( assigns ( :previous_inspection ) ) . to eq ( previous_inspection )
573+ # Prefilled fields would include the ground_clearance fields
574+ expect ( assigns ( :prefilled_fields ) ) . to be_an ( Array )
575+ end
576+ end
577+
578+ describe "get_prefill_objects for results tab" do
579+ it "handles results tab prefill correctly" do
580+ previous_inspection . update (
581+ passed : true ,
582+ risk_assessment : "Test risk"
583+ )
584+
585+ get "/inspections/#{ new_inspection . id } /edit" , params : { tab : "results" }
586+
587+ expect ( assigns ( :previous_inspection ) ) . to eq ( previous_inspection )
588+ # Results tab should only prefill specific fields
589+ expect ( response ) . to have_http_status ( :success )
590+ end
591+ end
592+ end
593+
594+ describe "validate_tab_parameter" do
595+ let ( :inspection ) { create ( :inspection , user : user , unit : unit ) }
596+
597+ it "redirects with invalid tab parameter" do
598+ get "/inspections/#{ inspection . id } /edit" , params : { tab : "invalid_tab" }
599+
600+ expect ( response ) . to redirect_to ( edit_inspection_path ( inspection ) )
601+ expect ( flash [ :alert ] ) . to be_present
602+ end
603+
604+ it "allows valid tab parameter" do
605+ get "/inspections/#{ inspection . id } /edit" , params : { tab : "user_height" }
606+
607+ expect ( response ) . to have_http_status ( :success )
608+ end
609+ end
610+
611+ describe "log_inspection_event error handling" do
612+ it "handles logging errors gracefully" do
613+ # Mock Event.log to raise an error
614+ allow ( Event ) . to receive ( :log ) . and_raise ( StandardError , "Database error" )
615+ allow ( Rails . logger ) . to receive ( :error )
616+
617+ # This should not raise an error
618+ post "/inspections" , params : {
619+ inspection : { unit_id : unit . id }
620+ }
621+
622+ expect ( Rails . logger ) . to have_received ( :error ) . with ( /Failed to log inspection event/ )
623+ # Request should still succeed
624+ expect ( response ) . to have_http_status ( :redirect )
625+ end
626+
627+ it "logs system events without specific inspection" do
628+ allow ( Event ) . to receive ( :log_system_event )
629+
630+ # CSV export logs a system event
631+ get "/inspections.csv"
632+
633+ expect ( Event ) . to have_received ( :log_system_event ) . with (
634+ hash_including (
635+ user : user ,
636+ action : "exported" ,
637+ metadata : hash_including ( resource_type : "Inspection" )
638+ )
639+ )
640+ end
641+ end
642+
643+ describe "calculate_changes" do
644+ let ( :inspection ) { create ( :inspection , user : user , unit : unit ) }
645+
646+ it "tracks changes correctly in update" do
647+ # Store original values
648+ original_passed = inspection . passed
649+ original_risk = inspection . risk_assessment
650+
651+ patch "/inspections/#{ inspection . id } " , params : {
652+ inspection : {
653+ passed : !original_passed ,
654+ risk_assessment : "New risk"
655+ }
656+ }
657+
658+ expect ( response ) . to redirect_to ( inspection_path ( inspection ) )
659+
660+ # Check the event was logged with changed data
661+ event = Event . for_resource ( inspection ) . last
662+ expect ( event . action ) . to eq ( "updated" )
663+ expect ( event . changed_data ) . to be_present
664+ expect ( event . changed_data [ "risk_assessment" ] ) . to be_present
665+ expect ( event . changed_data [ "risk_assessment" ] [ "to" ] ) . to eq ( "New risk" )
666+ end
667+
668+ it "ignores unchanged values" do
669+ original_value = inspection . risk_assessment
670+
671+ patch "/inspections/#{ inspection . id } " , params : {
672+ inspection : {
673+ risk_assessment : "New risk" ,
674+ passed : inspection . passed # Same value
675+ }
676+ }
677+
678+ expect ( response ) . to redirect_to ( inspection_path ( inspection ) )
679+
680+ # Check that only changed fields are in changed_data
681+ event = Event . for_resource ( inspection ) . last
682+ expect ( event . action ) . to eq ( "updated" )
683+ expect ( event . changed_data . keys ) . to include ( "risk_assessment" )
684+ expect ( event . changed_data . keys ) . not_to include ( "passed" )
685+ end
686+ end
687+
688+ describe "validate_inspection_completability" do
689+ context "with invalid complete inspection" do
690+ let ( :invalid_complete_inspection ) do
691+ # Create an inspection marked as complete but with missing data
692+ inspection = create ( :inspection , user : user , unit : unit )
693+ inspection . update_column ( :complete_date , Time . current ) # Bypass validations
694+ inspection
695+ end
696+
697+ before do
698+ allow_any_instance_of ( Inspection ) . to receive ( :can_mark_complete? ) . and_return ( false )
699+ allow_any_instance_of ( Inspection ) . to receive ( :completion_errors ) . and_return (
700+ [ "Missing inspection date" , "Unit not specified" ]
701+ )
702+ end
703+
704+ context "in development/test environment" do
705+ before { allow ( Rails . env ) . to receive ( :local? ) . and_return ( true ) }
706+
707+ it "raises error for invalid completion state" do
708+ expect {
709+ get "/inspections/#{ invalid_complete_inspection . id } "
710+ } . to raise_error ( StandardError , /DATA INTEGRITY ERROR/ )
711+ end
712+ end
713+
714+ context "in production environment" do
715+ before do
716+ allow ( Rails . env ) . to receive ( :local? ) . and_return ( false )
717+ allow ( Rails . logger ) . to receive ( :error )
718+ end
719+
720+ it "logs error but continues" do
721+ get "/inspections/#{ invalid_complete_inspection . id } "
722+
723+ expect ( Rails . logger ) . to have_received ( :error ) . with ( /DATA INTEGRITY ERROR/ )
724+ expect ( response ) . to have_http_status ( :success )
725+ end
726+ end
727+ end
728+ end
437729 end
438730
439731 describe "public routes (no authentication required)" do
0 commit comments