|
# frozen_string_literal: true |
|
|
|
# -- RAILS SETUP (ignore) -- |
|
|
|
require "bundler/inline" |
|
|
|
gemfile(true) do |
|
source "https://rubygems.org" |
|
|
|
git_source(:github) { |repo| "https://github.com/#{repo}.git" } |
|
|
|
gem "rails", github: "rails/rails", branch: "main" |
|
gem 'rspec-rails', '~> 4.0.2' |
|
gem "sqlite3" |
|
gem 'byebug' |
|
end |
|
|
|
require 'byebug' |
|
require "active_record" |
|
require "minitest/autorun" |
|
require "logger" |
|
require 'rails/all' |
|
|
|
# This connection will do for database-independent bug reports. |
|
ActiveRecord::Base.configurations = { "test" => { adapter: "sqlite3", database: "database.sqlite" } } |
|
ActiveRecord::Base.establish_connection ActiveRecord::Base.configurations['test'] |
|
ActiveRecord::Base.logger = Logger.new(STDOUT) |
|
|
|
# -- RAILS APP -- |
|
|
|
ActiveRecord::Schema.define do |
|
create_table :posts, force: true do |t| |
|
t.datetime :reviewed_at |
|
t.string :title, null: false |
|
end |
|
end |
|
|
|
# requires #reviewed_at:datetime column |
|
module Reviewable |
|
extend ActiveSupport::Concern |
|
|
|
included do |
|
scope :reviewed, -> { where.not(reviewed_at: nil) } |
|
scope :unreviewed, -> { where(reviewed_at: nil) } |
|
end |
|
|
|
def reviewed? |
|
reviewed_at.present? |
|
end |
|
|
|
def review(time = DateTime.current) |
|
update(reviewed_at: time) |
|
end |
|
end |
|
|
|
class Post < ActiveRecord::Base |
|
include Reviewable |
|
|
|
validates_presence_of :title |
|
end |
|
|
|
# -- RAILS SPEC HELPER -- |
|
|
|
module InMemoryDatabaseHelpers |
|
extend ActiveSupport::Concern |
|
|
|
class_methods do |
|
def switch_to_SQLite(&block) |
|
before(:all) { switch_to_in_memory_database(&block) } |
|
after(:all) { switch_back_to_test_database } |
|
end |
|
end |
|
|
|
private |
|
|
|
def switch_to_in_memory_database(&block) |
|
raise 'No migration given' unless block_given? |
|
|
|
ActiveRecord::Migration.verbose = false |
|
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") |
|
ActiveRecord::Schema.define(version: 1, &block) |
|
end |
|
|
|
def switch_back_to_test_database |
|
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) |
|
end |
|
end |
|
|
|
# -- RAILS SPEC SUITE -- |
|
|
|
# requires a :reviewable object |
|
shared_examples 'reviewable'do |
|
describe 'the interface' do |
|
subject { described_class.new } |
|
|
|
it 'has the correct interface' do |
|
expect(subject).to respond_to(:reviewed?) |
|
expect(subject).to respond_to(:review) |
|
expect(described_class).to respond_to(:reviewed) |
|
expect(described_class).to respond_to(:unreviewed) |
|
end |
|
end |
|
|
|
describe 'scopes' do |
|
let!(:records) { described_class.where(id: [reviewed, unreviewed]) } |
|
|
|
before do |
|
expect(reviewed.reviewed?).to eql true |
|
expect(unreviewed.reviewed?).to eql false |
|
end |
|
|
|
describe '.reviewed' do |
|
subject { records.reviewed } |
|
|
|
it { is_expected.to eq [reviewed] } |
|
end |
|
|
|
describe '.unreviewed' do |
|
subject { records.unreviewed } |
|
|
|
it { is_expected.to eq [unreviewed] } |
|
end |
|
end |
|
|
|
describe '#reviewed?' do |
|
subject { described_class.new } |
|
|
|
it 'returns the correct boolean based on #reviewed_at' do |
|
subject.reviewed_at = nil |
|
expect(subject.reviewed?).to eql false |
|
|
|
subject.reviewed_at = DateTime.current |
|
expect(subject.reviewed?).to eql true |
|
end |
|
end |
|
|
|
describe '#review' do |
|
let(:time) { DateTime.current } |
|
|
|
subject { unreviewed.review(time) } |
|
|
|
it 'updates the reviewed_at attribute' do |
|
expect { subject }.to change { unreviewed.reload.reviewed_at }.from(nil).to(time) |
|
end |
|
end |
|
end |
|
|
|
class FakeReviewable < ActiveRecord::Base |
|
include Reviewable |
|
end |
|
|
|
describe Reviewable do |
|
include InMemoryDatabaseHelpers |
|
|
|
switch_to_SQLite do |
|
create_table :fake_reviewables do |t| |
|
t.datetime :reviewed_at |
|
end |
|
end |
|
|
|
describe FakeReviewable, type: :model do |
|
include_examples 'reviewable' do |
|
let(:reviewed) { FakeReviewable.create! reviewed_at: DateTime.current } |
|
let(:unreviewed) { FakeReviewable.create! reviewed_at: nil } |
|
end |
|
end |
|
end |
|
|
|
# This example is at the end to show that the Rails app went back to the current testing database configuration defined in the setup |
|
describe Post do |
|
include_examples 'reviewable' do |
|
let(:reviewed) { Post.create! title: 'title1', reviewed_at: DateTime.current } |
|
let(:unreviewed) { Post.create! title: 'title2', reviewed_at: nil } |
|
end |
|
end |