mattbrictson / bundle_update_interactive

A stylish interactive mode for Bundler, inspired by `yarn upgrade-interactive`
MIT License
137 stars 3 forks source link

chore: add proper pluralization #39

Closed pacMakaveli closed 3 weeks ago

pacMakaveli commented 1 month ago

Hey @mattbrictson

I'm trying to write some tests for this update but I'm having issues getting the output to give me what I want.

      stdout, stderr, status = Dir.chdir(File.expand_path("../fixtures", __dir__)) do
        VCR.use_cassette("changelog_requests", :record => :new_episodes) do
          unchanged_lockfile = File.read("Gemfile.lock")

          BundlerCommands.expects(:parse_outdated).returns({ "rails" => "" })
          BundlerCommands.expects(:read_updated_lockfile).returns(unchanged_lockfile)
          mock_vulnerable_gems(['rails'])

          capture_io_and_exit_status do
            CLI.new.run(argv: [])
          end
        end
      end
      require 'pry'; binding.pry

      assert_equal(<<~EXPECTED_STDERR, stderr)
        Resolving latest gem versions...
        Checking for security vulnerabilities...
        Finding changelogs.
      EXPECTED_STDERR

      assert_match(/1 gem can be updated/, stdout)
      assert_nil(status)
    end

I tried this test to no avail. FYI, the BundlerCommands.expects(:parse_outdated).returns({ "rails" => "" }) was initially "sqlite3" => "2.0.3". I'm assuming it's something to do with stdin_data = " j j \n" or maybe my setup is not right.

Would you be able to help please?

mattbrictson commented 1 month ago

Hi @pacMakaveli, thanks for looking into this!

Right now cli_test.rb is pretty close to an integration test. It operates on a real Gemfile that is located in test/fixtures. The updatable gems are determined by comparing fixtures/Gemfile.lock with fixtures/Gemfile.lock.updated (the .updated fixture simulates what happens by running bundle lock --update).

The BundlerCommands.expects(:parse_outdated) mock is actually for a secondary feature of determining "withheld" gems, so changing that mock isn't going to affect the "gems can be updated" text.

I think the easiest way forward is:

Create a new copy of fixtures/Gemfile.lock.updated, maybe called fixtures/Gemfile.lock.updated-one, and manually edit it so that only one gem version is different from fixtures/Gemfile.lock. Then change the BundlerCommands.expects(:read_updated_lockfile) mock to return the contents of that new fixture.

Does that sound reasonable?

mattbrictson commented 3 weeks ago

@pacMakaveli I recently modified cli_test.rb on the main branch to make it closer to a pure unit test. To write your test, you should be able to use the stub_report helper, which makes setting up different scenarios easier now. See #41.

mattbrictson commented 3 weeks ago

Something like this:

def test_uses_correct_grammar_when_only_one_gem_can_be_updated
  report = stub_report(
    updatable_gems: {
      "sqlite3" => build(:outdated_gem, name: "sqlite3", changelog_uri: nil)
    }
  )
  report.expects(:scan_for_vulnerabilities!)

  stdout, = capture_io_and_exit_status(stdin_data: "\n") do
    CLI.new.run(argv: [])
  end

  assert_includes stdout, "1 gem can be updated"
end
pacMakaveli commented 3 weeks ago

Thanks @mattbrictson . I've not had a chance to look at it, but hopefully I can get to it by the end of today, specially with you doing most of my homework. 👯

pacMakaveli commented 3 weeks ago

Man, this broke me:

Color legend:
<inverse> Known security vulnerability
<red>     Major update; likely to have breaking changes, high risk
<yellow>  Minor update; changes and additions, moderate risk
<green>   Patch update; bug fixes, low risk
<cyan>    Possibly unreleased git commits; unknown risk

No gems to update.

Couldn't tell why it passes/fails but it turns out the expectation is Possibly unreleased git commits; unknown risk\n\n\e[?25l1 gems can be updated. I'm assuming it's shown if I go and select it or something?

pacMakaveli commented 3 weeks ago

Also, I had to add this in test_helper


require 'active_support/core_ext/module/delegation'
require 'active_support/inflector'

Otherwise I get this:

rake
/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/activesupport-7.2.0/lib/active_support/delegation.rb:47:in `generate': uninitialized constant #<Class:ActiveSupport::Delegation>::Inflector (NameError)

          unless Inflector.safe_constantize(to.name).equal?(to)
                 ^^^^^^^^^
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/activesupport-7.2.0/lib/active_support/core_ext/module/delegation.rb:161:in `delegate'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/factory_bot-6.4.5/lib/factory_bot/definition_hierarchy.rb:3:in `<class:DefinitionHierarchy>'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/factory_bot-6.4.5/lib/factory_bot/definition_hierarchy.rb:2:in `<module:FactoryBot>'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/factory_bot-6.4.5/lib/factory_bot/definition_hierarchy.rb:1:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:97:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:97:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.17/lib/zeitwerk/kernel.rb:34:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/factory_bot-6.4.5/lib/factory_bot.rb:8:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:160:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:160:in `rescue in require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:40:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.17/lib/zeitwerk/kernel.rb:34:in `require'
    from /Users/vlad/Projects/bundle_update_interactive/test/support/factory_bot.rb:3:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.17/lib/zeitwerk/kernel.rb:34:in `require'
    from /Users/vlad/Projects/bundle_update_interactive/test/test_helper.rb:9:in `block in <top (required)>'
    from /Users/vlad/Projects/bundle_update_interactive/test/test_helper.rb:9:in `each'
    from /Users/vlad/Projects/bundle_update_interactive/test/test_helper.rb:9:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from /Users/vlad/Projects/bundle_update_interactive/test/bundle_update_interactive/bundler_commands_test.rb:3:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:21:in `block in <main>'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:6:in `select'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:6:in `<main>'
<internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require': cannot load such file -- factory_bot (LoadError)
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.17/lib/zeitwerk/kernel.rb:34:in `require'
    from /Users/vlad/Projects/bundle_update_interactive/test/support/factory_bot.rb:3:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.17/lib/zeitwerk/kernel.rb:34:in `require'
    from /Users/vlad/Projects/bundle_update_interactive/test/test_helper.rb:9:in `block in <top (required)>'
    from /Users/vlad/Projects/bundle_update_interactive/test/test_helper.rb:9:in `each'
    from /Users/vlad/Projects/bundle_update_interactive/test/test_helper.rb:9:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from /Users/vlad/Projects/bundle_update_interactive/test/bundle_update_interactive/bundler_commands_test.rb:3:in `<top (required)>'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from <internal:/Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:86:in `require'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:21:in `block in <main>'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:6:in `select'
    from /Users/vlad/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb:6:in `<main>'
rake aborted!
Command failed with status (1)

Tasks: TOP => default => test
(See full trace by running task with --trace)