aboutsummaryrefslogtreecommitdiffstats
path: root/railties/test/application/console_test.rb
blob: 7dc9d0083fe66738fee59f942c689171067a536c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# frozen_string_literal: true
require "isolation/abstract_unit"

class ConsoleTest < ActiveSupport::TestCase
  include ActiveSupport::Testing::Isolation

  def setup
    build_app
  end

  def teardown
    teardown_app
  end

  def load_environment(sandbox = false)
    require "#{rails_root}/config/environment"
    Rails.application.sandbox = sandbox
    Rails.application.load_console
  end

  def irb_context
    Object.new.extend(Rails::ConsoleMethods)
  end

  def test_app_method_should_return_integration_session
    TestHelpers::Rack.send :remove_method, :app
    load_environment
    console_session = irb_context.app
    assert_instance_of ActionDispatch::Integration::Session, console_session
  end

  def test_app_can_access_path_helper_method
    app_file "config/routes.rb", <<-RUBY
      Rails.application.routes.draw do
        get 'foo', to: 'foo#index'
      end
    RUBY

    load_environment
    console_session = irb_context.app
    assert_equal "/foo", console_session.foo_path
  end

  def test_new_session_should_return_integration_session
    load_environment
    session = irb_context.new_session
    assert_instance_of ActionDispatch::Integration::Session, session
  end

  def test_reload_should_fire_preparation_and_cleanup_callbacks
    load_environment
    a = b = c = nil

    # TODO: These should be defined on the initializer
    ActiveSupport::Reloader.to_complete { a = b = c = 1 }
    ActiveSupport::Reloader.to_complete { b = c = 2 }
    ActiveSupport::Reloader.to_prepare { c = 3 }

    irb_context.reload!(false)

    assert_equal 1, a
    assert_equal 2, b
    assert_equal 3, c
  end

  def test_reload_should_reload_constants
    app_file "app/models/user.rb", <<-MODEL
      class User
        attr_accessor :name
      end
    MODEL

    load_environment
    assert User.new.respond_to?(:name)

    app_file "app/models/user.rb", <<-MODEL
      class User
        attr_accessor :name, :age
      end
    MODEL

    assert !User.new.respond_to?(:age)
    irb_context.reload!(false)
    assert User.new.respond_to?(:age)
  end

  def test_access_to_helpers
    load_environment
    helper = irb_context.helper
    assert_not_nil helper
    assert_instance_of ActionView::Base, helper
    assert_equal "Once upon a time in a world...",
      helper.truncate("Once upon a time in a world far far away")
  end
end

begin
  require "pty"
rescue LoadError
end

class FullStackConsoleTest < ActiveSupport::TestCase
  def setup
    skip "PTY unavailable" unless defined?(PTY) && PTY.respond_to?(:open)

    build_app
    app_file "app/models/post.rb", <<-CODE
      class Post < ActiveRecord::Base
      end
    CODE
    system "#{app_path}/bin/rails runner 'Post.connection.create_table :posts'"

    @master, @slave = PTY.open
  end

  def teardown
    teardown_app
  end

  def assert_output(expected, timeout = 1)
    timeout = Time.now + timeout

    output = ""
    until output.include?(expected) || Time.now > timeout
      if IO.select([@master], [], [], 0.1)
        output << @master.read(1)
      end
    end

    assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}"
  end

  def write_prompt(command, expected_output = nil)
    @master.puts command
    assert_output command
    assert_output expected_output if expected_output
    assert_output "> "
  end

  def spawn_console(options)
    Process.spawn(
      "#{app_path}/bin/rails console #{options}",
      in: @slave, out: @slave, err: @slave
    )

    assert_output "> ", 30
  end

  def test_sandbox
    spawn_console("--sandbox")

    write_prompt "Post.count", "=> 0"
    write_prompt "Post.create"
    write_prompt "Post.count", "=> 1"
    @master.puts "quit"

    spawn_console("--sandbox")

    write_prompt "Post.count", "=> 0"
    write_prompt "Post.transaction { Post.create; raise }"
    write_prompt "Post.count", "=> 0"
    @master.puts "quit"
  end

  def test_environment_option_and_irb_option
    spawn_console("test -- --verbose")

    write_prompt "a = 1", "a = 1"
    write_prompt "puts Rails.env", "puts Rails.env\r\ntest"
    @master.puts "quit"
  end
end