diff --git a/Gemfile b/Gemfile index f5ec0667..0e88c864 100644 --- a/Gemfile +++ b/Gemfile @@ -83,3 +83,4 @@ gem 'importmap-rails' gem 'turbo-rails' gem 'stimulus-rails' gem 'will_paginate' +gem 'telegram-bot-ruby', '~> 1.0' diff --git a/Gemfile.lock b/Gemfile.lock index 352421c1..4f4d3531 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -163,6 +163,25 @@ GEM dotenv-rails (2.8.1) dotenv (= 2.8.1) railties (>= 3.2) + dry-core (1.0.0) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.0.0) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-struct (1.6.0) + dry-core (~> 1.0, < 2) + dry-types (>= 1.7, < 2) + ice_nine (~> 0.11) + zeitwerk (~> 2.6) + dry-types (1.7.1) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) ed25519 (1.3.0) em-websocket (0.5.3) eventmachine (>= 0.12.9) @@ -178,6 +197,13 @@ GEM railties (>= 3.0.0) faker (3.2.1) i18n (>= 1.8.11, < 2) + faraday (2.7.12) + base64 + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (3.0.2) ffi (1.16.3) formatador (1.1.0) friendly_id (5.4.2) @@ -232,6 +258,7 @@ GEM hub (1.12.4) i18n (1.14.1) concurrent-ruby (~> 1.0) + ice_nine (0.11.2) importmap-rails (1.2.1) actionpack (>= 6.0.0) railties (>= 6.0.0) @@ -271,6 +298,7 @@ GEM mini_portile2 (2.8.5) minitest (5.20.0) multi_json (1.15.0) + multipart-post (2.3.0) nenv (0.3.0) net-imap (0.4.2) date @@ -410,6 +438,7 @@ GEM rubocop-ast (1.29.0) parser (>= 3.2.1.0) ruby-progressbar (1.13.0) + ruby2_keywords (0.0.5) ruby_parser (3.20.3) sexp_processor (~> 4.16) rubyzip (2.3.2) @@ -458,6 +487,11 @@ GEM stimulus-rails (1.3.0) railties (>= 6.0.0) stringio (3.0.8) + telegram-bot-ruby (1.0.0) + dry-struct (~> 1.6) + faraday (~> 2.0) + faraday-multipart (~> 1.0) + zeitwerk (~> 2.6) temple (0.10.3) thor (1.3.0) tilt (2.3.0) @@ -557,6 +591,7 @@ DEPENDENCIES spring-commands-rspec sprockets stimulus-rails + telegram-bot-ruby (~> 1.0) turbo-rails uglifier webdrivers diff --git a/app/assets/javascripts/bots.coffee b/app/assets/javascripts/bots.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/bots.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/bots.scss b/app/assets/stylesheets/bots.scss new file mode 100644 index 00000000..3cc9db3d --- /dev/null +++ b/app/assets/stylesheets/bots.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Bots controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ diff --git a/app/controllers/bots_controller.rb b/app/controllers/bots_controller.rb new file mode 100644 index 00000000..5b41c6e5 --- /dev/null +++ b/app/controllers/bots_controller.rb @@ -0,0 +1,71 @@ +class BotsController < ApplicationController + before_action :set_bot, only: %i[ show edit update destroy ] + + # GET /bots or /bots.json + def index + authorize @bots = policy_scope(Bot) + end + + # GET /bots/1 or /bots/1.json + def show + authorize @bot + end + + # GET /bots/new + def new + authorize @bot = current_user.bots.new + end + + # GET /bots/1/edit + def edit + end + + # POST /bots or /bots.json + def create + authorize @bot = Bot.new(bot_params) + + respond_to do |format| + if @bot.save + format.html { redirect_to bot_url(@bot), notice: "Bot was successfully created." } + format.json { render :show, status: :created, location: @bot } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @bot.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /bots/1 or /bots/1.json + def update + respond_to do |format| + if @bot.update(bot_params) + format.html { redirect_to bot_url(@bot), notice: "Bot was successfully updated." } + format.json { render :show, status: :ok, location: @bot } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @bot.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /bots/1 or /bots/1.json + def destroy + @bot.destroy + + respond_to do |format| + format.html { redirect_to bots_url, notice: "Bot was successfully destroyed." } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_bot + @bot = Bot.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def bot_params + params.require(:bot).permit(:name, :telegram_api_token, :discord_api_token, :user_id, :profile_id) + end +end diff --git a/app/helpers/bots_helper.rb b/app/helpers/bots_helper.rb new file mode 100644 index 00000000..5f9665c0 --- /dev/null +++ b/app/helpers/bots_helper.rb @@ -0,0 +1,2 @@ +module BotsHelper +end diff --git a/app/models/bot.rb b/app/models/bot.rb new file mode 100644 index 00000000..19d09f9e --- /dev/null +++ b/app/models/bot.rb @@ -0,0 +1,41 @@ +require 'telegram/bot' +class Bot < ActiveRecord::Base + belongs_to :user + belongs_to :profile, optional: true + + # def send_text + # if self.telegram_api_token + # Telegram::Bot::Client.run(telegram_api_token) do |bot| + # bot.api.send_message(chat_id: message.chat.id, text: response_text, parse_mode: "Markdown") + # end + # end + # end + + def fortune + `fortune -a` + end + + def telegram_listen + return unless self.telegram_api_token + Telegram::Bot::Client.run(telegram_api_token) do |bot| + bot.listen do |message| + # TODO Logging + # File.open("./logs/#{@botname}.log", 'a') { |f| f.write(["\n", Time.now, message.chat.id, message.from.id, message.from.first_name, message].join("\t")) } + case message + when Telegram::Bot::Types::Message + # Debugging use next to skip/drop the queue + # next + case message.text + when /^\/fortune/i + response_text = `fortune -a` + begin + bot.api.send_message(chat_id: message.chat.id, reply_to_message_id: message.message_id, text: response_text, parse_mode: "Markdown") + rescue + puts "Error from fortune" + end + end + end + end + end + end +end diff --git a/app/models/profile.rb b/app/models/profile.rb index 91a51475..d27e3ca0 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -6,6 +6,7 @@ class Profile < ActiveRecord::Base dependent: :destroy # has_many :followers, through: :passive_relationships, source: :follower has_many :microposts, as: :micropostable + has_many :bots def followers Relationship.where("followable_id = ? AND followable_type = ?", self.id, self.class.to_s) diff --git a/app/models/user.rb b/app/models/user.rb index 0860e07d..57f2c002 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,6 +14,7 @@ class User < ActiveRecord::Base has_many :following_profiles, through: :active_relationships, source: :followable, source_type: "Profile" has_many :following_projects, through: :active_relationships, source: :followable, source_type: "Project" has_many :microposts, as: :micropostable + has_many :bots def icid stp = SoftTokenPrincipal.where(soft_token: self.soft_token).first_or_initialize diff --git a/app/policies/bot_policy.rb b/app/policies/bot_policy.rb new file mode 100644 index 00000000..12536a41 --- /dev/null +++ b/app/policies/bot_policy.rb @@ -0,0 +1,55 @@ +class BotPolicy + attr_reader :user, :model + + def initialize(user, model) + @user = user || User.new + @bot = model + end + + class Scope + def initialize(user, scope) + @user = user + @scope = scope + end + + def resolve + if user.admin? + scope.all + else + scope.all + end + end + + private + + attr_reader :user, :scope + end + + def index? + @user.admin? + end + + def show? + @user.admin? || @user == @bot.user + end + + def new? + @user.admin? + end + + def create? + @user.admin? + end + + def edit? + @user.admin? || @user == @bot.user + end + + def update? + @user.admin? || @user == @bot.user + end + + def destroy? + @user.admin? || @user == @bot.user + end +end diff --git a/app/views/bots/_bot.json.jbuilder b/app/views/bots/_bot.json.jbuilder new file mode 100644 index 00000000..df054cda --- /dev/null +++ b/app/views/bots/_bot.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! bot, :id, :name, :telegram_api_token, :discord_api_token, :user_id, :profile_id, :created_at, :updated_at +json.url bot_url(bot, format: :json) diff --git a/app/views/bots/_form.html.haml b/app/views/bots/_form.html.haml new file mode 100644 index 00000000..83ae8f21 --- /dev/null +++ b/app/views/bots/_form.html.haml @@ -0,0 +1,12 @@ += simple_form_for(@bot) do |f| + = f.error_notification + + .form-inputs + = f.input :name + = f.input :telegram_api_token + = f.input :discord_api_token + = f.hidden_field :user_id + = f.association :profile + + .form-actions + = f.button :submit diff --git a/app/views/bots/edit.html.haml b/app/views/bots/edit.html.haml new file mode 100644 index 00000000..93fbd65b --- /dev/null +++ b/app/views/bots/edit.html.haml @@ -0,0 +1,7 @@ +%h1 Editing bot + += render 'form' + += link_to 'Show', @bot +\| += link_to 'Back', bots_path diff --git a/app/views/bots/index.html.haml b/app/views/bots/index.html.haml new file mode 100644 index 00000000..79c2c046 --- /dev/null +++ b/app/views/bots/index.html.haml @@ -0,0 +1,51 @@ +.contain + %h1 Listing bots + + %div{style: "align-self: start;"} + - if policy(Bot).new? + = link_to '+ New Bot', new_bot_path + +.contain + - @bots.each do |bot| + = link_to bot, class: "bot" do + %h1= bot.name + -# %span= bot.summary + -# .social-links + - bot.social_links.each do |social_link| + = social_link.to_icon.html_safe + -# %p= bot.about + -# %span #{bot.followers.count} Followers + -#    + -# %span #{bot.microposts.count} Posts + - if policy(bot).destroy? + = link_to 'Edit', edit_bot_path(bot) + = link_to 'Delete', bot, method: :delete, data: { confirm: 'Are you sure?' } +-# %h1 Listing bots + +-# %table +-# %thead +-# %tr +-# %th Name +-# %th Telegram api token +-# %th Discord api token +-# %th User +-# %th Profile +-# %th +-# %th +-# %th + +-# %tbody +-# - @bots.each do |bot| +-# %tr +-# %td= bot.name +-# %td= bot.telegram_api_token +-# %td= bot.discord_api_token +-# %td= bot.user +-# %td= bot.profile +-# %td= link_to 'Show', bot +-# %td= link_to 'Edit', edit_bot_path(bot) +-# %td= link_to 'Destroy', bot, method: :delete, data: { confirm: 'Are you sure?' } + +-# %br + +-# = link_to 'New Bot', new_bot_path diff --git a/app/views/bots/index.json.jbuilder b/app/views/bots/index.json.jbuilder new file mode 100644 index 00000000..dcd45319 --- /dev/null +++ b/app/views/bots/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @bots, partial: "bots/bot", as: :bot diff --git a/app/views/bots/new.html.haml b/app/views/bots/new.html.haml new file mode 100644 index 00000000..8c672290 --- /dev/null +++ b/app/views/bots/new.html.haml @@ -0,0 +1,5 @@ +%h1 New bot + += render 'form' + += link_to 'Back', bots_path diff --git a/app/views/bots/show.html.haml b/app/views/bots/show.html.haml new file mode 100644 index 00000000..c0edeea1 --- /dev/null +++ b/app/views/bots/show.html.haml @@ -0,0 +1,21 @@ +.contain + %span 🤖 + %h1 + = @bot.name + - if policy(@bot).edit? + = link_to 'Edit', edit_bot_path(@bot) + + %p + %b Telegram api token: + = @bot.telegram_api_token + %p + %b Discord api token: + = @bot.discord_api_token + %p + %b User: + = link_to @bot.user, @bot.user + - if @bot.profile + %p + %b Profile: + = link_to @bot.profile.display_name, @bot.profile + diff --git a/app/views/bots/show.json.jbuilder b/app/views/bots/show.json.jbuilder new file mode 100644 index 00000000..b4468322 --- /dev/null +++ b/app/views/bots/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "bots/bot", bot: @bot diff --git a/app/views/layouts/_navigation_links.html.erb b/app/views/layouts/_navigation_links.html.erb index 80210a40..111d6e9c 100644 --- a/app/views/layouts/_navigation_links.html.erb +++ b/app/views/layouts/_navigation_links.html.erb @@ -8,6 +8,9 @@
  • <%= link_to 'Profiles', profiles_path %>
  • <%= link_to 'Projects', projects_path %>
  • <%= link_to 'Doodads', doodads_path, data: { turbo: false } %>
  • + <% if policy(:bot).index? %> +
  • <%= link_to 'Bots', bots_path %>
  • + <% end %> <% if policy(:table).index? %>
  • <%= link_to 'Tables', tables_path %>
  • <% end %> diff --git a/config/routes.rb b/config/routes.rb index 6d4066d7..8ef25716 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :bots resources :social_links resources :profiles do member do diff --git a/db/migrate/20231126154137_create_bots.rb b/db/migrate/20231126154137_create_bots.rb new file mode 100644 index 00000000..9be70389 --- /dev/null +++ b/db/migrate/20231126154137_create_bots.rb @@ -0,0 +1,13 @@ +class CreateBots < ActiveRecord::Migration[6.1] + def change + create_table :bots do |t| + t.string :name + t.string :telegram_api_token + t.string :discord_api_token + t.belongs_to :user, null: false, foreign_key: true + t.belongs_to :profile, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6c191d46..16b45bce 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,11 +10,23 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_11_22_115709) do +ActiveRecord::Schema.define(version: 2023_11_26_154137) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "bots", force: :cascade do |t| + t.string "name" + t.string "telegram_api_token" + t.string "discord_api_token" + t.bigint "user_id", null: false + t.bigint "profile_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["profile_id"], name: "index_bots_on_profile_id" + t.index ["user_id"], name: "index_bots_on_user_id" + end + create_table "canisters", force: :cascade do |t| t.string "icid" t.string "name" @@ -224,6 +236,8 @@ ActiveRecord::Schema.define(version: 2023_11_22_115709) do t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + add_foreign_key "bots", "profiles" + add_foreign_key "bots", "users" add_foreign_key "canisters", "users" add_foreign_key "doodads", "users" add_foreign_key "profiles", "users" diff --git a/spec/factories/bots.rb b/spec/factories/bots.rb new file mode 100644 index 00000000..d363c9ec --- /dev/null +++ b/spec/factories/bots.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + factory :bot do + name "MyString" + telegram_api_token "MyString" + discord_api_token "MyString" + user nil + profile nil + end +end diff --git a/spec/helpers/bots_helper_spec.rb b/spec/helpers/bots_helper_spec.rb new file mode 100644 index 00000000..d28be7e0 --- /dev/null +++ b/spec/helpers/bots_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the BotsHelper. For example: +# +# describe BotsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe BotsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/bot_spec.rb b/spec/models/bot_spec.rb new file mode 100644 index 00000000..c66d9e2b --- /dev/null +++ b/spec/models/bot_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Bot, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/bots_spec.rb b/spec/requests/bots_spec.rb new file mode 100644 index 00000000..51ea0df1 --- /dev/null +++ b/spec/requests/bots_spec.rb @@ -0,0 +1,135 @@ +require 'rails_helper' + +# This spec was generated by rspec-rails when you ran the scaffold generator. +# It demonstrates how one might use RSpec to test the controller code that +# was generated by Rails when you ran the scaffold generator. +# +# It assumes that the implementation code is generated by the rails scaffold +# generator. If you are using any extension libraries to generate different +# controller code, this generated spec may or may not pass. +# +# It only uses APIs available in rails and/or rspec-rails. There are a number +# of tools you can use to make these specs even more expressive, but we're +# sticking to rails and rspec-rails APIs to keep things simple and stable. + +RSpec.describe "/bots", type: :request do + + # This should return the minimal set of attributes required to create a valid + # Bot. As you add validations to Bot, be sure to + # adjust the attributes here as well. + let(:valid_attributes) { + skip("Add a hash of attributes valid for your model") + } + + let(:invalid_attributes) { + skip("Add a hash of attributes invalid for your model") + } + + describe "GET /index" do + it "renders a successful response" do + Bot.create! valid_attributes + get bots_url + expect(response).to be_successful + end + end + + describe "GET /show" do + it "renders a successful response" do + bot = Bot.create! valid_attributes + get bot_url(bot) + expect(response).to be_successful + end + end + + describe "GET /new" do + it "renders a successful response" do + get new_bot_url + expect(response).to be_successful + end + end + + describe "GET /edit" do + it "renders a successful response" do + bot = Bot.create! valid_attributes + get edit_bot_url(bot) + expect(response).to be_successful + end + end + + describe "POST /create" do + context "with valid parameters" do + it "creates a new Bot" do + expect { + post bots_url, params: { bot: valid_attributes } + }.to change(Bot, :count).by(1) + end + + it "redirects to the created bot" do + post bots_url, params: { bot: valid_attributes } + expect(response).to redirect_to(bot_url(Bot.last)) + end + end + + context "with invalid parameters" do + it "does not create a new Bot" do + expect { + post bots_url, params: { bot: invalid_attributes } + }.to change(Bot, :count).by(0) + end + + + it "renders a successful response (i.e. to display the 'new' template)" do + post bots_url, params: { bot: invalid_attributes } + expect(response).to be_successful + end + + end + end + + describe "PATCH /update" do + context "with valid parameters" do + let(:new_attributes) { + skip("Add a hash of attributes valid for your model") + } + + it "updates the requested bot" do + bot = Bot.create! valid_attributes + patch bot_url(bot), params: { bot: new_attributes } + bot.reload + skip("Add assertions for updated state") + end + + it "redirects to the bot" do + bot = Bot.create! valid_attributes + patch bot_url(bot), params: { bot: new_attributes } + bot.reload + expect(response).to redirect_to(bot_url(bot)) + end + end + + context "with invalid parameters" do + + it "renders a successful response (i.e. to display the 'edit' template)" do + bot = Bot.create! valid_attributes + patch bot_url(bot), params: { bot: invalid_attributes } + expect(response).to be_successful + end + + end + end + + describe "DELETE /destroy" do + it "destroys the requested bot" do + bot = Bot.create! valid_attributes + expect { + delete bot_url(bot) + }.to change(Bot, :count).by(-1) + end + + it "redirects to the bots list" do + bot = Bot.create! valid_attributes + delete bot_url(bot) + expect(response).to redirect_to(bots_url) + end + end +end diff --git a/spec/routing/bots_routing_spec.rb b/spec/routing/bots_routing_spec.rb new file mode 100644 index 00000000..38b4129d --- /dev/null +++ b/spec/routing/bots_routing_spec.rb @@ -0,0 +1,38 @@ +require "rails_helper" + +RSpec.describe BotsController, type: :routing do + describe "routing" do + it "routes to #index" do + expect(get: "/bots").to route_to("bots#index") + end + + it "routes to #new" do + expect(get: "/bots/new").to route_to("bots#new") + end + + it "routes to #show" do + expect(get: "/bots/1").to route_to("bots#show", id: "1") + end + + it "routes to #edit" do + expect(get: "/bots/1/edit").to route_to("bots#edit", id: "1") + end + + + it "routes to #create" do + expect(post: "/bots").to route_to("bots#create") + end + + it "routes to #update via PUT" do + expect(put: "/bots/1").to route_to("bots#update", id: "1") + end + + it "routes to #update via PATCH" do + expect(patch: "/bots/1").to route_to("bots#update", id: "1") + end + + it "routes to #destroy" do + expect(delete: "/bots/1").to route_to("bots#destroy", id: "1") + end + end +end diff --git a/spec/views/bots/edit.html.haml_spec.rb b/spec/views/bots/edit.html.haml_spec.rb new file mode 100644 index 00000000..6f031d2e --- /dev/null +++ b/spec/views/bots/edit.html.haml_spec.rb @@ -0,0 +1,34 @@ +require 'rails_helper' + +RSpec.describe "bots/edit", type: :view do + let(:bot) { + Bot.create!( + name: "MyString", + telegram_api_token: "MyString", + discord_api_token: "MyString", + user: nil, + profile: nil + ) + } + + before(:each) do + assign(:bot, bot) + end + + it "renders the edit bot form" do + render + + assert_select "form[action=?][method=?]", bot_path(bot), "post" do + + assert_select "input[name=?]", "bot[name]" + + assert_select "input[name=?]", "bot[telegram_api_token]" + + assert_select "input[name=?]", "bot[discord_api_token]" + + assert_select "input[name=?]", "bot[user_id]" + + assert_select "input[name=?]", "bot[profile_id]" + end + end +end diff --git a/spec/views/bots/index.html.haml_spec.rb b/spec/views/bots/index.html.haml_spec.rb new file mode 100644 index 00000000..0ecbd5e6 --- /dev/null +++ b/spec/views/bots/index.html.haml_spec.rb @@ -0,0 +1,32 @@ +require 'rails_helper' + +RSpec.describe "bots/index", type: :view do + before(:each) do + assign(:bots, [ + Bot.create!( + name: "Name", + telegram_api_token: "Telegram Api Token", + discord_api_token: "Discord Api Token", + user: nil, + profile: nil + ), + Bot.create!( + name: "Name", + telegram_api_token: "Telegram Api Token", + discord_api_token: "Discord Api Token", + user: nil, + profile: nil + ) + ]) + end + + it "renders a list of bots" do + render + cell_selector = Rails::VERSION::STRING >= '7' ? 'div>p' : 'tr>td' + assert_select cell_selector, text: Regexp.new("Name".to_s), count: 2 + assert_select cell_selector, text: Regexp.new("Telegram Api Token".to_s), count: 2 + assert_select cell_selector, text: Regexp.new("Discord Api Token".to_s), count: 2 + assert_select cell_selector, text: Regexp.new(nil.to_s), count: 2 + assert_select cell_selector, text: Regexp.new(nil.to_s), count: 2 + end +end diff --git a/spec/views/bots/new.html.haml_spec.rb b/spec/views/bots/new.html.haml_spec.rb new file mode 100644 index 00000000..274fda1a --- /dev/null +++ b/spec/views/bots/new.html.haml_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe "bots/new", type: :view do + before(:each) do + assign(:bot, Bot.new( + name: "MyString", + telegram_api_token: "MyString", + discord_api_token: "MyString", + user: nil, + profile: nil + )) + end + + it "renders new bot form" do + render + + assert_select "form[action=?][method=?]", bots_path, "post" do + + assert_select "input[name=?]", "bot[name]" + + assert_select "input[name=?]", "bot[telegram_api_token]" + + assert_select "input[name=?]", "bot[discord_api_token]" + + assert_select "input[name=?]", "bot[user_id]" + + assert_select "input[name=?]", "bot[profile_id]" + end + end +end diff --git a/spec/views/bots/show.html.haml_spec.rb b/spec/views/bots/show.html.haml_spec.rb new file mode 100644 index 00000000..d5143c39 --- /dev/null +++ b/spec/views/bots/show.html.haml_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe "bots/show", type: :view do + before(:each) do + assign(:bot, Bot.create!( + name: "Name", + telegram_api_token: "Telegram Api Token", + discord_api_token: "Discord Api Token", + user: nil, + profile: nil + )) + end + + it "renders attributes in

    " do + render + expect(rendered).to match(/Name/) + expect(rendered).to match(/Telegram Api Token/) + expect(rendered).to match(/Discord Api Token/) + expect(rendered).to match(//) + expect(rendered).to match(//) + end +end