diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a13be3851..cea3e33d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,9 @@ jobs: bundler-cache: true - name: Install system dependencies - run: sudo apt-get install -y libvips42 libvips-dev imagemagick + run: | + sudo apt-get update + sudo apt-get install -y libvips42 libvips-dev imagemagick - uses: actions/setup-node@v1 with: diff --git a/app/controllers/account/calculators_controller.rb b/app/controllers/account/calculators_controller.rb index dec87775d..4a1cd4b6a 100644 --- a/app/controllers/account/calculators_controller.rb +++ b/app/controllers/account/calculators_controller.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class Account::CalculatorsController < Account::BaseController - before_action :resource, only: [:edit, :update, :destroy] load_and_authorize_resource def index @@ -23,6 +22,8 @@ def new end def edit + @calculator = resource + collect_fields_for_form end @@ -37,6 +38,8 @@ def create end def update + @calculator = resource + if updater redirect_to edit_account_calculator_path(slug: @calculator), notice: t("notifications.calculator_updated") else @@ -47,6 +50,8 @@ def update end def destroy + @calculator = resource + @calculator.destroy redirect_to account_calculators_path, notice: t("notifications.calculator_deleted"), status: :see_other @@ -59,7 +64,7 @@ def collection end def resource - Calculator.find(params[:slug]) + collection.friendly.find(params[:slug]) end def collect_fields_for_form diff --git a/app/controllers/api/v2/calculators_controller.rb b/app/controllers/api/v2/calculators_controller.rb deleted file mode 100644 index d1a48a6e7..000000000 --- a/app/controllers/api/v2/calculators_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class Api::V2::CalculatorsController < ApplicationController - def compute - @fields = Calculator.find_by(slug: params["id"]).fields.result - - render json: @fields, root: "result", adapter: :json - end -end diff --git a/app/lib/calculation_resolver.rb b/app/lib/calculation_resolver.rb deleted file mode 100644 index ba74bcb65..000000000 --- a/app/lib/calculation_resolver.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require "functions/items_per_month" -require "functions/since" - -class CalculationResolver - attr_reader :calculator - - def initialize - @calculator = Dentaku::Calculator.new - @calculator.add_function(:since, :numeric, Since.calculate_units) - @calculator.add_function(:items_per_month, :numeric, ItemsPerMonth.deferred) - end - - def result(parameters, value) - calculator.evaluate( - value, - calculator.dependencies(value).index_by do |key| - key.to_sym - end.merge(parameters) - ) - end -end diff --git a/app/lib/calculator_resolver.rb b/app/lib/calculator_resolver.rb deleted file mode 100644 index 30777b0f1..000000000 --- a/app/lib/calculator_resolver.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -class CalculatorResolver - def self.call(calculator) - get_fields(calculator).each_with_object({}) do |field, hash| - unless field[:type] == "Calculation" - hash[field] = [] - - next - end - upcased_dependencies = upcase_dependencies(field[:value]) - hash[field] = all_dependent_values(upcased_dependencies) - end - end - - def self.all_dependent_values(dependencies) - dependent_values = [] - - if dependent_values(dependencies).present? - dependent_values(dependencies).each do |value| - dependent_values << value - end - end - - return dependent_values if dependent_calculations(dependencies).blank? - - dependent_calculations(dependencies).each do |nested_calculation| - nested_dependencies = upcase_dependencies(nested_calculation[:value]) - dependent_values += all_dependent_values(nested_dependencies) - end - - dependent_values - end - - def self.upcase_dependencies(value) - selectors = CalculationResolver.new.calculator.dependencies(value) - - selectors.map!(&:upcase) - end - - def self.dependent_values(value) - selectors = upcase_dependencies(value) - - Value.where(selector: selectors) - end - - def self.dependent_calculations(value) - selectors = upcase_dependencies(value) - - Calculation.where(selector: selectors) - end - - def self.get_fields(calculator) - calculator.fields.result - end - - class << self - private :all_dependent_values, :dependent_values, - :dependent_calculations, :upcase_dependencies, - :get_fields - end -end diff --git a/app/models/calculation.rb b/app/models/calculation.rb deleted file mode 100644 index 3f749c47e..000000000 --- a/app/models/calculation.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -class Calculation < Field - validates :value, length: { minimum: 2 } -end diff --git a/app/models/calculator.rb b/app/models/calculator.rb index 89a774a2a..d6e72e586 100644 --- a/app/models/calculator.rb +++ b/app/models/calculator.rb @@ -27,8 +27,8 @@ class Calculator < ApplicationRecord has_many :fields, dependent: :destroy has_many :formulas, dependent: :destroy - accepts_nested_attributes_for :fields, reject_if: :all_blank, allow_destroy: true - accepts_nested_attributes_for :formulas, reject_if: :all_blank, allow_destroy: true + accepts_nested_attributes_for :fields, allow_destroy: true + accepts_nested_attributes_for :formulas, allow_destroy: true scope :ordered_by_name, -> { order(:en_name) } diff --git a/app/models/category.rb b/app/models/category.rb index d0257c014..4aab34f78 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -24,16 +24,20 @@ # class Category < ApplicationRecord include Translatable + translates :name - belongs_to :field + PRIORITY_RANGE = 0..10 - translates :name + belongs_to :field, optional: true + has_many :diapers_periods, dependent: :destroy + has_many :category_categoryables, dependent: :restrict_with_exception + + enum :preferable, { not_preferable: false, preferable: true } validates :uk_name, :en_name, presence: true validates :uk_name, :en_name, length: { minimum: 3, maximum: 30 }, format: { with: /\A[\p{L}0-9\s'-]+\z/i }, - uniqueness: { case_sensitive: false }, allow_blank: true validates :priority, numericality: { greater_than_or_equal_to: 0 } diff --git a/app/models/named_value.rb b/app/models/named_value.rb deleted file mode 100644 index a31931db9..000000000 --- a/app/models/named_value.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -class NamedValue < Field - validates :name, length: { minimum: 2 } - validates :from, :to, numericality: { only_integer: true } -end diff --git a/app/models/range_field.rb b/app/models/range_field.rb deleted file mode 100644 index d4bf59cf3..000000000 --- a/app/models/range_field.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -class RangeField < Field - validates :value, length: { minimum: 1 } - validates :from, :to, numericality: { only_integer: true } -end diff --git a/app/models/select.rb b/app/models/select.rb deleted file mode 100644 index 9d311d04c..000000000 --- a/app/models/select.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -class Select < Field - validates :label, length: { minimum: 2 } -end diff --git a/app/models/value.rb b/app/models/value.rb deleted file mode 100644 index 62b211561..000000000 --- a/app/models/value.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -class Value < Field - validates :value, format: { with: /[a-zA-Z0-9]/ } - validates :value, length: { minimum: 1 } -end diff --git a/app/serializers/field_serializer.rb b/app/serializers/field_serializer.rb deleted file mode 100644 index 637c75cb6..000000000 --- a/app/serializers/field_serializer.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -class FieldSerializer < ActiveModel::Serializer - attributes :name, :result - - def name - object.name.parameterize.underscore - end - - # rubocop:disable Metrics/AbcSize - def result - cal_res = CalculatorResolver.call(object.calculator) - res = cal_res.each_with_object({}) do |(key, value), result| - result[key[:value]] = value.each_with_object({}) do |v, sel| - sel[v[:selector].downcase] = v[:value] - end - end - result = res.each_with_object({}) do |(formula, parameters), new_hash| - new_hash[formula] = CalculationResolver.new.result(parameters, formula) - end - answer = result.each_with_object([]) do |(_, calculated_formula), new_array| - new_array << calculated_formula - end - number = "" - (0..answer.count).each do |el| - number = answer[el] if object.selector == "R#{el + 1}" - end - number - end - # rubocop:enable Metrics/AbcSize -end diff --git a/db/migrate/20241119192344_change_field_in_category.rb b/db/migrate/20241119192344_change_field_in_category.rb new file mode 100644 index 000000000..c5b85556c --- /dev/null +++ b/db/migrate/20241119192344_change_field_in_category.rb @@ -0,0 +1,5 @@ +class ChangeFieldInCategory < ActiveRecord::Migration[7.2] + def change + change_column_null :categories, :field_id, true + end +end diff --git a/db/schema.rb b/db/schema.rb index d530131b1..e9e42b813 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_11_07_140542) do +ActiveRecord::Schema[7.2].define(version: 2024_11_19_192344) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -59,7 +59,7 @@ t.integer "priority", default: 0, null: false t.string "en_name" t.decimal "price", precision: 10, scale: 2, default: "0.0", null: false - t.bigint "field_id", null: false + t.bigint "field_id" t.boolean "preferable", default: false, null: false t.index ["field_id"], name: "index_categories_on_field_id" end diff --git a/spec/factories/calculators.rb b/spec/factories/calculators.rb index 76607bb4b..35ede4765 100644 --- a/spec/factories/calculators.rb +++ b/spec/factories/calculators.rb @@ -19,6 +19,5 @@ factory :calculator do en_name { "English Calculator" } uk_name { "Український калькуялтор" } - slug { "calculator" } end end diff --git a/spec/factories/fields.rb b/spec/factories/fields.rb index 78e5c2ec7..41e2abf45 100644 --- a/spec/factories/fields.rb +++ b/spec/factories/fields.rb @@ -24,7 +24,7 @@ # FactoryBot.define do factory :field do - kind { 0 } + kind { "number" } en_label { "Label" } uk_label { "Label" } var_name { "var" } diff --git a/spec/features/account/calculators_spec.rb b/spec/features/account/calculators_spec.rb index 615a23bfb..7b57c5da3 100644 --- a/spec/features/account/calculators_spec.rb +++ b/spec/features/account/calculators_spec.rb @@ -3,8 +3,8 @@ require "rails_helper" describe "visit admin page", js: true do - let!(:diapers_calculator) { create(:calculator, en_name: "Diapers Calculator", slug: "diapers") } - let!(:napkin_calculator) { create(:calculator, en_name: "Napkin Calculator", slug: "napkin") } + let!(:diapers_calculator) { create(:calculator, en_name: "Diapers Calculator") } + let!(:napkin_calculator) { create(:calculator, en_name: "Napkin Calculator") } include_context :authorize_admin diff --git a/spec/features/show_calculator_spec.rb b/spec/features/show_calculator_spec.rb index 5fe98128a..45ff97fda 100644 --- a/spec/features/show_calculator_spec.rb +++ b/spec/features/show_calculator_spec.rb @@ -8,20 +8,6 @@ allow(controller).to receive(:resource).and_return(calculator) end - context "when result parameter is present" do - it "assigns @result with the value from params" do - get :show, params: { slug: calculator.slug, result: "42", locale: :en } - expect(assigns(:result)).to eq("42") - end - end - - context "when result parameter is not present" do - it "assigns @result as nil" do - get :show, params: { slug: calculator.slug, locale: :en } - expect(assigns(:result)).to be_nil - end - end - it "assigns the correct calculator to @calculator" do get :show, params: { slug: calculator.slug, locale: :en } expect(assigns(:calculator)).to eq(calculator) diff --git a/spec/lib/calculation_resolver_spec.rb b/spec/lib/calculation_resolver_spec.rb deleted file mode 100644 index 448eaddbb..000000000 --- a/spec/lib/calculation_resolver_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require "rails_helper" - -RSpec.describe CalculationResolver do - subject { described_class } - - describe "#result" do - let(:value) { "P1 + 2" } - let(:parameters) { { p1: 2 } } - let(:calculator) { create(:calculator) } - let(:calculation) do - create(:calculation, value: value, calculator: calculator) - end - - subject { CalculationResolver.new.result(parameters, calculation.value) } - - context "when pass valid data" do - it { is_expected.to eq 4 } - end - - context "when pass empty hash" do - let(:parameters) { {} } - - it { is_expected.to be_nil } - end - - context "when pass upcase letter in hash " do - let(:parameters) { { P1: 2 } } - - it { is_expected.to eq 4 } - end - - context "when pass value with `since` formula" do - let(:from) { Date.new(2020, 0o1, 0o1) } - let(:to) { Date.new(2021, 0o1, 31) } - let(:value) { "SINCE(#{from}, #{to}, 'day')" } - - it { is_expected.to eq 396 } - end - - context "when pass value with `items_per_month` formula" do - let(:value) { "ITEMS_PER_MONTH(P1, F1, F2)" } - let(:parameters) { { p1: 5 } } - - before do - create(:range_field, - selector: "F1", - from: 0, - to: 2, - value: "30", - label: "label", - kind: "form", - calculator: calculator) - create(:range_field, - selector: "F2", - from: 3, - to: 5, - value: "70", - label: "label", - kind: "form", - calculator: calculator) - end - - it { is_expected.to eq(300) } - end - end -end diff --git a/spec/lib/calculator_resolver_spec.rb b/spec/lib/calculator_resolver_spec.rb deleted file mode 100644 index ab3af1d5e..000000000 --- a/spec/lib/calculator_resolver_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require "rails_helper" - -RSpec.describe CalculatorResolver do - subject { described_class } - - let(:calculator) { build(:calculator) } - let!(:calculation_r1) { create(:calculation, value: "P1 * P2 / P3", type: "Calculation", selector: "R1", label: "one", kind: "result", calculator: calculator) } - let!(:calculation_r2) { create(:calculation, value: "10 * P4", type: "Calculation", selector: "R2", label: "one", kind: "result", calculator: calculator) } - let!(:calculation_p4) { create(:value, value: "P1 * P5", type: "Calculation", selector: "P4", label: "four", kind: "parameter", calculator: calculator) } - let!(:calculation_p5) { create(:value, value: "P2 * P6", type: "Calculation", selector: "P5", label: "four", kind: "parameter", calculator: calculator) } - let!(:value_r3) { create(:value, value: "Value", type: "Value", selector: "R3", label: "two", kind: "result", calculator: calculator) } - let!(:value_p1) { create(:value, value: "Value", type: "Value", selector: "P1", label: "three", kind: "parameter", calculator: calculator) } - let!(:value_p2) { create(:value, value: "Value", type: "Value", selector: "P2", label: "four", kind: "parameter", calculator: calculator) } - let!(:value_p3) { create(:value, value: "Value", type: "Value", selector: "P3", label: "five", kind: "parameter", calculator: calculator) } - let!(:value_p6) { create(:value, value: "Value", type: "Value", selector: "P6", label: "six", kind: "parameter", calculator: calculator) } - - describe "#call" do - it { expect(CalculatorResolver.call(calculator)).to be_kind_of(Hash) } - - context "when 'field' is 'Calculation'" do - it { expect(CalculatorResolver.call(calculator)[calculation_r1]).to match_array([value_p1, value_p2, value_p3]) } - end - - context "when 'field' is not 'Calculation'" do - it { expect(CalculatorResolver.call(calculator)[value_r3]).to be_empty } - end - - context "when 'Calculation' contains deep-level nested dependecies" do - it { expect(CalculatorResolver.call(calculator)[calculation_r2]).to match_array([value_p1, value_p2, value_p6]) } - end - end -end diff --git a/spec/models/calculation_spec.rb b/spec/models/calculation_spec.rb deleted file mode 100644 index 0fd58311a..000000000 --- a/spec/models/calculation_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -require "rails_helper" - -RSpec.describe Calculation, type: :model do - let(:local_prefix_calculation) { "activerecord.errors.models.calculation.attributes" } - - subject(:calculation) { create(:calculation) } - - describe "validations" do - it { is_expected.to be_valid } - it { - is_expected.to validate_presence_of(:value).with_message(I18n - .t("#{local_prefix_calculation}.value.too_short")) - } - it { - is_expected.to validate_length_of(:value).is_at_least(2).with_message(I18n - .t("#{local_prefix_calculation}.value.too_short")) - } - end -end diff --git a/spec/models/calculator_spec.rb b/spec/models/calculator_spec.rb index fda8d9538..6be5b5005 100644 --- a/spec/models/calculator_spec.rb +++ b/spec/models/calculator_spec.rb @@ -27,7 +27,6 @@ it { is_expected.to validate_length_of(:en_name).is_at_least(3).is_at_most(50) } it { is_expected.to validate_presence_of(:uk_name) } it { is_expected.to validate_length_of(:uk_name).is_at_least(3).is_at_most(50) } - it { is_expected.to validate_presence_of(:slug) } it { is_expected.to validate_uniqueness_of(:slug) } end @@ -35,37 +34,4 @@ it { is_expected.to have_many(:fields).dependent(:destroy) } it { is_expected.to have_many(:formulas).dependent(:destroy) } end - - describe "scope" do - context "finds instances by slug and name" do - let!(:calc) { create(:calculator, slug: "calc") } - let!(:calc2) { create(:calculator, slug: "diapers", name: "Calculator") } - - it "finds two instances by slug or name" do - expect(Calculator.by_name_or_slug("calc").to_a).to include(calc, calc2) - end - - it "returns all instances when search params are empty" do - expect(Calculator.by_name_or_slug(" ").to_a).to include(calc, calc2) - end - - it "returns all instances when search params are nil" do - expect(Calculator.by_name_or_slug(nil).to_a).to include(calc, calc2) - end - - it "does not find any instances" do - expect(Calculator.by_name_or_slug("qwerty").to_a).to eq [] - end - end - end - - describe "versioning", versioning: true do - let!(:calculator) { create(:calculator, name: "Calculator 1") } - - it "adds a version when the calculator is updated" do - calculator.update!(name: "Calculator 2") - - expect(calculator.versions.count).to eq(2) - end - end end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 1a8326fc8..b1c84ca96 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -32,10 +32,8 @@ describe "validations" do it { is_expected.to validate_presence_of(:en_name) } it { is_expected.to validate_length_of(:en_name).is_at_least(3).is_at_most(30) } - it { is_expected.to validate_uniqueness_of(:en_name).case_insensitive } it { is_expected.to validate_presence_of(:uk_name) } it { is_expected.to validate_length_of(:uk_name).is_at_least(3).is_at_most(30) } - it { is_expected.to validate_uniqueness_of(:uk_name).case_insensitive } it { is_expected.to validate_numericality_of(:priority).is_greater_than_or_equal_to(0) } end diff --git a/spec/models/field_spec.rb b/spec/models/field_spec.rb index da220cd8b..076818980 100644 --- a/spec/models/field_spec.rb +++ b/spec/models/field_spec.rb @@ -43,7 +43,8 @@ } it { is_expected.to define_enum_for(:kind) - .with_values([:number, :category]) + .with_values(number: "number", category: "category") + .backed_by_column_of_type(:string) } it { is_expected.to define_enum_for(:unit) @@ -87,25 +88,4 @@ describe "associations" do it { is_expected.to belong_to(:calculator) } end - - describe "#set_selector" do - let(:calculator) { create(:calculator) } - let(:field) { build(:field, label: "new", kind: 0, calculator: calculator) } - - context "when there is no form fields in a database" do - it "generates selector with one letter and a number" do - expect { field.save }.to change { field.selector }.from(nil).to("F1") - end - end - - context "when there are more forms fields in a database" do - before do - create(:field, label: "new", kind: 0, calculator: calculator) - end - - it "generates selector with one letter and an increased number" do - expect { field.save }.to change { field.selector }.from(nil).to("F2") - end - end - end end diff --git a/spec/models/named_value_spec.rb b/spec/models/named_value_spec.rb deleted file mode 100644 index a96b24ef9..000000000 --- a/spec/models/named_value_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -require "rails_helper" - -RSpec.describe NamedValue, type: :model do - let(:local_prefix_named_value) { "activerecord.errors.models.named_value.attributes" } - - subject(:named_value) { create(:named_value) } - - describe "validations" do - it { - is_expected.to validate_presence_of(:name).with_message(I18n - .t("#{local_prefix_named_value}.name.too_short")) - } - it { - is_expected.to validate_length_of(:name).is_at_least(2).with_message(I18n - .t("#{local_prefix_named_value}.name.too_short")) - } - it { - is_expected.to validate_numericality_of(:from) - .only_integer - .with_message(I18n.t("#{local_prefix_named_value}.from.not_a_number")) - } - it { - is_expected.to validate_numericality_of(:to) - .only_integer - .with_message(I18n.t("#{local_prefix_named_value}.to.not_an_integer")) - } - it { - is_expected.to validate_presence_of(:from) - .with_message(I18n.t("#{local_prefix_named_value}.from.not_an_integer")) - } - it { - is_expected.to validate_presence_of(:to) - .with_message(I18n.t("#{local_prefix_named_value}.to.not_an_integer")) - } - end -end diff --git a/spec/models/range_field_spec.rb b/spec/models/range_field_spec.rb deleted file mode 100644 index db4c0a05e..000000000 --- a/spec/models/range_field_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -require "rails_helper" - -RSpec.describe RangeField, type: :model do - let(:local_prefix_range_field) { "activerecord.errors.models.range_field.attributes" } - - subject { create(:range_field) } - - describe "validations" do - it { - is_expected.to validate_numericality_of(:from) - .only_integer - .with_message(I18n.t("#{local_prefix_range_field}.from.not_a_number")) - } - it { - is_expected.to validate_numericality_of(:to) - .only_integer - .with_message(I18n.t("#{local_prefix_range_field}.to.not_an_integer")) - } - it { - is_expected.to validate_length_of(:value) - .is_at_least(1) - .with_message(I18n.t("#{local_prefix_range_field}.value.too_short")) - } - it { - is_expected.to validate_presence_of(:from) - .with_message(I18n.t("#{local_prefix_range_field}.from.not_an_integer")) - } - it { - is_expected.to validate_presence_of(:to) - .with_message(I18n.t("#{local_prefix_range_field}.to.not_an_integer")) - } - it { - is_expected.to validate_presence_of(:value) - .with_message(I18n.t("#{local_prefix_range_field}.value.too_short")) - } - end -end diff --git a/spec/models/select_spec.rb b/spec/models/select_spec.rb deleted file mode 100644 index af70b771a..000000000 --- a/spec/models/select_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -require "rails_helper" - -RSpec.describe Select, type: :model do - describe "validations" do - context "with a valid label length of 2 characters" do - subject { build(:select, label: "ab") } - - it { is_expected.to be_valid } - end - - context "with a label of less than 2 characters" do - subject(:select) { build(:select, label: "a") } - - it "is not valid" do - select.valid? - - expect(select.errors[:label]).to include("is too short (minimum is 2 characters)") - end - end - end -end diff --git a/spec/models/value_spec.rb b/spec/models/value_spec.rb deleted file mode 100644 index e961fedd2..000000000 --- a/spec/models/value_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: fields -# -# id :bigint not null, primary key -# en_label :string default(""), not null -# kind :string not null -# uk_label :string default(""), not null -# unit :integer default("day") -# var_name :string default(""), not null -# created_at :datetime not null -# updated_at :datetime not null -# calculator_id :bigint not null -# -# Indexes -# -# index_fields_on_calculator_id (calculator_id) -# -# Foreign Keys -# -# fk_rails_... (calculator_id => calculators.id) -# -require "rails_helper" - -RSpec.describe Value, type: :model do - let(:local_prefix_value) { "activerecord.errors.models.value.attributes" } - - subject { create(:value) } - - describe "validations" do - it { is_expected.to be_valid } - it { - is_expected.to validate_presence_of(:value).with_message(I18n - .t("#{local_prefix_value}.value.too_short")) - } - it { is_expected.to allow_value("Value").for(:value) } - it { - is_expected.to validate_length_of(:value).is_at_least(1).with_message(I18n - .t("#{local_prefix_value}.value.too_short")) - } - it { - is_expected.not_to allow_value(".*+/+/").for(:value).with_message(I18n - .t("#{local_prefix_value}.value.invalid")) - } - end -end diff --git a/spec/requests/calculators_spec.rb b/spec/requests/calculators_spec.rb index dacbea773..94c13fc1b 100644 --- a/spec/requests/calculators_spec.rb +++ b/spec/requests/calculators_spec.rb @@ -4,61 +4,6 @@ RSpec.describe CalculatorsController, type: :request do let(:calculator) { create(:calculator) } - let!(:calculation_r1) do - create(:calculation, value: "P1 * P2 / P3", type: "Calculation", - selector: "R1", name: "First result", - label: "one", kind: "result", calculator: calculator) - end - let!(:calculation_r2) do - create(:calculation, value: "10 * P4", type: "Calculation", selector: "R2", - name: "Second result", - label: "one", kind: "result", calculator: calculator) - end - let!(:calculation_p2) do - create(:calculation, value: "10 * P4", type: "Calculation", selector: "P2", - label: "one", kind: "parameter", - calculator: calculator) - end - let!(:value_r3) do - create(:value, value: "Value", type: "Value", selector: "R3", - name: "Third result", - label: "two", kind: "result", calculator: calculator) - end - let!(:value_p1) do - create(:value, value: "Value", type: "Value", selector: "P1", - label: "three", - kind: "parameter", calculator: calculator) - end - let(:json_response) { response.parsed_body } - - describe "POST api/v2/calculators/PERMALINK/compute" do - before do - post compute_api_v2_calculator_path(calculator) - end - - it "returns JSON" do - expect(response).to be_successful - expect(response.content_type).to eq("application/json; charset=utf-8") - - expect(json_response).to include("result") - expect(json_response["result"][0]).to include("name", "result") - end - - it "JSON response contains 'result' in the root" do - expect(json_response["result"]).to be_truthy - end - - it "JSON response contains 'name' and 'result' attributes" do - expect(json_response["result"][0].keys).to contain_exactly( - "name", - "result" - ) - end - - it "JSON response contains field 'name' in snake case format" do - expect(json_response["result"][0]["name"]).to eq("first_result") - end - end describe "GET #index" do context "when show_calculators_list feature is enabled" do @@ -113,8 +58,8 @@ describe "POST #create" do include_context :authorize_admin - let(:valid_attributes) { { name: "калькулятор", slug: "test" } } - let(:invalid_attributes) { { name: "$калькулятор", slug: "test" } } + let(:valid_attributes) { { en_name: "calculator", uk_name: "калькулятор" } } + let(:invalid_attributes) { { en_name: "", uk_name: "" } } context "with valid attributes" do it "creates a calculator" do @@ -133,7 +78,7 @@ post account_calculators_path, params: { calculator: invalid_attributes } end.not_to change(Calculator, :count) - expect(response.body).to include(I18n.t("activerecord.errors.models.calculator.attributes.name.invalid")) + expect(response.body).to include(I18n.t("errors.messages.too_short", count: 3)) expect(response).to render_template(:new) end end diff --git a/spec/requests/result_calculators_spec.rb b/spec/requests/result_calculators_spec.rb deleted file mode 100644 index 5ebc43a50..000000000 --- a/spec/requests/result_calculators_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -require "rails_helper" - -RSpec.describe Api::V2::CalculatorsController, type: :request do - let(:calculator) { create(:calculator) } - let!(:value_p1) do - create(:value, value: "10", type: "Value", selector: "P1", label: "one", - kind: "parameter", - calculator: calculator) - end - let!(:value_p2) do - create(:value, value: "20", type: "Value", selector: "P2", label: "two", - kind: "parameter", - calculator: calculator) - end - let!(:value_p3) do - create(:value, value: "50", type: "Value", selector: "P3", label: "three", - kind: "parameter", - calculator: calculator) - end - let!(:value_p4) do - create(:value, value: "60", type: "Value", selector: "P4", label: "four", - kind: "parameter", - calculator: calculator) - end - let(:json_response) { response.parsed_body } - - describe "POST api/v2/calculators/PERMALINK/compute" do - before do - create(:range_field, selector: "F1", from: 0, to: 3, value: "300", - label: "label", kind: "form", calculator: calculator) - create(:range_field, selector: "F2", from: 4, to: 6, value: "240", - label: "label", kind: "form", calculator: calculator) - create(:range_field, selector: "F3", from: 7, to: 12, value: "180", - label: "label", kind: "form", calculator: calculator) - create(:range_field, selector: "F4", from: 13, to: 24, value: "120", - label: "label", kind: "form", calculator: calculator) - create(:range_field, selector: "F6", from: 25, to: 30, value: "60", - label: "label", kind: "form", calculator: calculator) - create(:value, value: "10", selector: "F7", label: "one", - kind: "parameter", - calculator: calculator) - - create(:calculation, value: "ITEMS_PER_MONTH(P1, F1, F2, F3, F4, F5, F6)", - selector: "R1", name: "Diapers amount used to date", - label: "one", kind: "result", calculator: calculator) - create(:calculation, value: "10 + P4 ", type: "Calculation", selector: "R2", - name: "Second result", label: "one", kind: "result", - calculator: calculator) - create(:calculation, value: "10 + P2 ", type: "Calculation", selector: "R3", - name: "Third result", label: "one", kind: "result", - calculator: calculator) - - post compute_api_v2_calculator_path(calculator) - end - - it "http 200" do - expect(response.status).to eql(200) - end - it "result of calculation_r1 is 20" do - expect(json_response["result"][0]["result"]).to eq(2640) - end - it "result of calculation_r2 is 70" do - expect(json_response["result"][1]["result"]).to eq(70) - expect(json_response["result"][1].values).to contain_exactly( - "second_result", 70 - ) - end - it "result of calculation_r3 is 30" do - expect(json_response["result"][2]["result"]).to eq(30) - expect(json_response["result"][2].values).to contain_exactly( - "third_result", 30 - ) - end - it do - expect(json_response["result"][0]["result"]).to be_kind_of(Numeric) - end - end -end