spec/unit/attribute_spec.rb in attr_masker-0.2.1 vs spec/unit/attribute_spec.rb in attr_masker-0.3.0

- old
+ new

@@ -14,21 +14,21 @@ expect(retval.model).to eq(:some_model) expect(retval.options).to eq(opts) end end - describe "#column_name" do - subject { receiver.method :column_name } + describe "#column_names" do + subject { receiver.method :column_names } let(:receiver) { described_class.new :some_attr, :some_model, options } let(:options) { {} } - it "defaults to attribute name" do - expect(subject.call).to eq(:some_attr) + it "defaults to array containing attribute name only" do + expect(subject.call).to contain_exactly(:some_attr) end - it "can be overriden with :column_name option" do - options[:column_name] = :some_column + it "can be overriden with :column_names option" do + options[:column_names] = :some_column expect(subject.call).to eq(:some_column) end end describe "#should_mask?" do @@ -51,9 +51,91 @@ def retval_for_opts(opts) receiver = described_class.new(:some_attr, :some_model, opts) callable = subject.bind(receiver) callable.(model_instance) end + end + + describe "mask" do + subject { described_class.instance_method :mask } + let(:receiver) { described_class.new :some_attr, :some_model, options } + let(:model_instance) { Struct.new(:some_attr).new("value") } + let(:options) { { masker: masker } } + let(:masker) { ->(**) { "masked_value" } } + + it "takes the instance.options[:masker] and calls it" do + expect(masker).to receive(:call) + subject.bind(receiver).call(model_instance) + end + + it "passes the unmarshalled attribute value to the masker" do + expect(receiver).to receive(:unmarshal_data). + with("value").and_return("unmarshalled_value") + expect(masker).to receive(:call). + with(hash_including(value: "unmarshalled_value")) + subject.bind(receiver).call(model_instance) + end + + it "passes the model instance to the masker" do + expect(masker).to receive(:call). + with(hash_including(model: model_instance)) + subject.bind(receiver).call(model_instance) + end + + it "passes the attribute name to the masker" do + expect(masker).to receive(:call). + with(hash_including(attribute_name: :some_attr)) + subject.bind(receiver).call(model_instance) + end + + it "passes the masking options to the masker" do + expect(masker).to receive(:call). + with(hash_including(masking_options: options)) + subject.bind(receiver).call(model_instance) + end + + it "marshals the masked value, and assigns it to the attribute" do + expect(receiver).to receive(:marshal_data). + with("masked_value").and_return("marshalled_masked_value") + subject.bind(receiver).call(model_instance) + expect(model_instance.some_attr).to eq("marshalled_masked_value") + end + end + + describe "#masked_attributes_new_values" do + subject { receiver.method :masked_attributes_new_values } + let(:receiver) { described_class.new :some_attr, :some_model, options } + let(:options) { {} } + let(:model_instance) { double } # Struct.new(:some_attr, :other_attr) } + let(:changes) { { some_attr: [nil, "new"], other_attr: [nil, "other"] } } + + before { allow(model_instance).to receive(:changes).and_return(changes) } + + # rubocop:disable Style/BracesAroundHashParameters + # We are comparing hashes here, and we want hash literals + it "returns a hash of required database updates which include masked field \ + change, but ignores other attribute changes" do + expect(subject.(model_instance)).to eq({ some_attr: "new" }) + end + + it "returns an emtpy hash for an unchanged object" do + changes.clear + expect(subject.(model_instance)).to eq({}) + end + + it "allows overriding column/field name to be updated with column_name \ + option" do + options[:column_names] = %i[other_attr] + expect(subject.(model_instance)).to eq({ other_attr: "other" }) + end + + it "allows specifying more than one column/field name to be updated \ + with column_name option" do + options[:column_names] = %i[some_attr other_attr] + expect(subject.(model_instance)). + to eq({ some_attr: "new", other_attr: "other" }) + end + # rubocop:enable Style/BracesAroundHashParameters end describe "#evaluate_option" do subject { receiver.method :evaluate_option } let(:receiver) { described_class.new :some_attr, model_instance, options }