Skip to content

Commit fe863b6

Browse files
justin808claude
andcommitted
Add unit tests for wrap_console_script_with_nonce method
Adds comprehensive unit tests for the wrap_console_script_with_nonce helper method to ensure proper CSP nonce handling across different Rails versions. Test coverage includes: - CSP nonce attribute generation when available - Script tag creation without nonce when CSP is not configured - Rails 5.2-6.0 compatibility fallback (ArgumentError handling) - Blank input handling (empty, nil, whitespace) - Multi-line script preservation (newlines maintained) - Special character escaping in script content These tests validate the cross-version Rails compatibility logic (5.2-7.x) that is critical infrastructure code for the CSP nonce support feature. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 1b8e964 commit fe863b6

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

spec/dummy/spec/helpers/react_on_rails_helper_spec.rb

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,5 +751,124 @@ def helper.append_javascript_pack_tag(name, **options)
751751
end
752752
end
753753
end
754+
755+
describe "#wrap_console_script_with_nonce" do
756+
let(:helper) { PlainReactOnRailsHelper.new }
757+
let(:console_script) { "console.log.apply(console, ['[SERVER] test message']);" }
758+
759+
context "when CSP nonce is available" do
760+
before do
761+
def helper.respond_to?(method_name, *args)
762+
return true if method_name == :content_security_policy_nonce
763+
764+
super
765+
end
766+
767+
def helper.content_security_policy_nonce(_directive = nil)
768+
"abc123"
769+
end
770+
end
771+
772+
it "wraps script with nonce attribute" do
773+
result = helper.send(:wrap_console_script_with_nonce, console_script)
774+
expect(result).to include('nonce="abc123"')
775+
expect(result).to include('id="consoleReplayLog"')
776+
expect(result).to include(console_script)
777+
end
778+
779+
it "creates a valid script tag" do
780+
result = helper.send(:wrap_console_script_with_nonce, console_script)
781+
expect(result).to match(%r{<script.*id="consoleReplayLog".*>.*</script>})
782+
end
783+
end
784+
785+
context "when CSP is not configured" do
786+
before do
787+
allow(helper).to receive(:respond_to?).and_call_original
788+
allow(helper).to receive(:respond_to?).with(:content_security_policy_nonce).and_return(false)
789+
end
790+
791+
it "wraps script without nonce attribute" do
792+
result = helper.send(:wrap_console_script_with_nonce, console_script)
793+
expect(result).not_to include("nonce=")
794+
expect(result).to include('id="consoleReplayLog"')
795+
expect(result).to include(console_script)
796+
end
797+
end
798+
799+
context "with Rails 5.2-6.0 compatibility (ArgumentError fallback)" do
800+
before do
801+
def helper.respond_to?(method_name, *args)
802+
return true if method_name == :content_security_policy_nonce
803+
804+
super
805+
end
806+
807+
def helper.content_security_policy_nonce(*args)
808+
raise ArgumentError if args.any?
809+
810+
"fallback123"
811+
end
812+
end
813+
814+
it "falls back to no-argument method" do
815+
result = helper.send(:wrap_console_script_with_nonce, console_script)
816+
expect(result).to include('nonce="fallback123"')
817+
end
818+
end
819+
820+
context "with blank input" do
821+
it "returns empty string for empty input" do
822+
expect(helper.send(:wrap_console_script_with_nonce, "")).to eq("")
823+
end
824+
825+
it "returns empty string for nil input" do
826+
expect(helper.send(:wrap_console_script_with_nonce, nil)).to eq("")
827+
end
828+
829+
it "returns empty string for whitespace-only input" do
830+
expect(helper.send(:wrap_console_script_with_nonce, " ")).to eq("")
831+
end
832+
end
833+
834+
context "with multiple console statements" do
835+
let(:multi_line_script) do
836+
<<~JS.strip
837+
console.log.apply(console, ['[SERVER] line 1']);
838+
console.log.apply(console, ['[SERVER] line 2']);
839+
console.error.apply(console, ['[SERVER] error']);
840+
JS
841+
end
842+
843+
before do
844+
allow(helper).to receive(:respond_to?).and_call_original
845+
allow(helper).to receive(:respond_to?).with(:content_security_policy_nonce).and_return(false)
846+
end
847+
848+
it "preserves newlines in multi-line script" do
849+
result = helper.send(:wrap_console_script_with_nonce, multi_line_script)
850+
expect(result).to include("line 1")
851+
expect(result).to include("line 2")
852+
expect(result).to include("error")
853+
# Verify newlines are preserved (not collapsed)
854+
expect(result.scan(/console\.(log|error)\.apply/).count).to eq(3)
855+
end
856+
end
857+
858+
context "with special characters in script" do
859+
let(:script_with_quotes) { %q{console.log.apply(console, ['[SERVER] "quoted" text']);} }
860+
861+
before do
862+
allow(helper).to receive(:respond_to?).and_call_original
863+
allow(helper).to receive(:respond_to?).with(:content_security_policy_nonce).and_return(false)
864+
end
865+
866+
it "properly escapes content in script tag" do
867+
result = helper.send(:wrap_console_script_with_nonce, script_with_quotes)
868+
expect(result).to include(script_with_quotes)
869+
expect(result).to match(%r{<script.*>.*"quoted".*</script>})
870+
end
871+
end
872+
end
754873
end
755874
# rubocop:enable Metrics/BlockLength

0 commit comments

Comments
 (0)