require "rspec" require "json" require "dry-types" require "dry-validation" module Types include Dry::Types.module RegionCode = Types::Strict::String.constrained( format: /\A(au|nz|uk|ie)\z/, ) end class OpenSettlement < Dry::Types::Value attribute :region_code, Types::RegionCode attribute :period_ending_on, Types::Strict::Date end class ArgSchemas def self.[](struct) Dry::Validation.Form do struct.schema.each { |attr, type| key(attr).required(type) } end end end PayloadSchema = Dry::Validation.Form do key(:command).required(inclusion?: %w(OpenSettlement)) key(:args).required(:hash?) rule(open_settlement_args: [:command, :args]) do |command, args| command.eql?('OpenSettlement').then(args.schema(ArgSchemas[OpenSettlement])) end end class CommandsController attr_reader :payload def initialize(payload) @payload = payload end def call PayloadSchema.call(payload).messages end end RSpec.describe "command enqueuing" do it "errors with an empty payload" do payload = {} controller = CommandsController.new(payload) errors = controller.call expect(errors).to eq( command: ["is missing", "must be one of: OpenSettlement"], args: ["is missing"], ) end it "errors when command is missing from payload" do payload = { args: {}, } controller = CommandsController.new(payload) errors = controller.call expect(errors).to eq( command: ["is missing", "must be one of: OpenSettlement"], args: ["must be filled"] ) end it "errors with an invalid set of args" do payload = { command: "OpenSettlement", args: { region_code: "au", }, } controller = CommandsController.new(payload) errors = controller.call expect(errors).to eq( args: { period_ending_on: ["is missing"], }, ) end it "validates correct params" do payload = { command: "OpenSettlement", args: { region_code: "au", period_ending_on: "2016-03-31", } } controller = CommandsController.new(payload) errors = controller.call expect(errors).to be_empty end end