1

I'm writing a ruby gem using Commander which uses erb templates and $terminal.color for some of the output. When writing tests in RSpec (using CLI Test) I'd like to be able to pass an option to my commands to prevent the colorization so that my tests can match simple strings instead of having to include formatting in my string comparisons.

Currently I'm using:

execute_script('mycommand arg1')
expect(last_execution.stdout).to include("Expected Colorized Output")

But let's say the word "Colorized" is bolded, this test will fail because its surrounded by other characters so I have to write my test like this

execute_script('mycommand arg1')
expect(last_execution.stdout).to include("Expected")
expect(last_execution.stdout).to include("Colorized")
expect(last_execution.stdout).to include("Output")

I'd like to avoid having to break up the test in this way -- is there a way I can either pass an option within my execute_script call in my tests, or configure RSpec to remove formatting for tests?

Sample string that RSpec sees

# successfully is bolded here
Command ran \e[1m\e[32msuccessfully\e[0m

Which I would like to be able to run against

expect(last_execution.stdout).to include("Command ran successfully")
Rabbott
  • 4,282
  • 1
  • 30
  • 53
  • Can you wrap `include("Expected Colorized Output")` with colorization somehow, like `include(bold(red("Expected Colorized Output")))` --- literally making up this syntax, but something along those line will work, perhaps? – jefflunt Aug 04 '16 at 14:46
  • Well the idea is that the template itself doesn't matter, so if its red or green or bold, the test will still pass. The template 'design' could change quite a bit, but the copy wont. – Rabbott Aug 04 '16 at 14:49
  • Hm. Can you include the raw output (that is visible to rspec) in your question? I.e. print `last_execution.stdout` to the console so you (and us) can see what rspec is seeing? – jefflunt Aug 04 '16 at 14:52
  • Updated the question with an example – Rabbott Aug 04 '16 at 14:58
  • Ah. Perhaps you can simply test for the string `successfully`, since that indicates the status, and is an unbroken string within the colorization. – jefflunt Aug 04 '16 at 15:00
  • That's what I'm doing, and specify in the question that I'm trying to avoid that. – Rabbott Aug 04 '16 at 15:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120140/discussion-between-jefflunt-and-rabbott). – jefflunt Aug 04 '16 at 15:06

2 Answers2

2

Try to remove ANSI escape symbols from the string with the following RegExp: /\e\[(\d+)m/

"Command ran \e[1m\e[32msuccessfully\e[0m".gsub(/\e\[(\d+)m/, "")
 => "Command ran successfully"

RegExp was taken from ansi gem https://github.com/rubyworks/ansi

https://github.com/rubyworks/ansi/blob/17002348d45ce9298a1a4017dc43d3cf65151bd4/lib/ansi/code.rb#L44

https://github.com/rubyworks/ansi/blob/17002348d45ce9298a1a4017dc43d3cf65151bd4/lib/ansi/code.rb#L193-L208

I am not sure if this regexp is the most correct for this job. I found another in this answer: How can I remove the ANSI escape sequences from a string in python

/(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]/

Answer refers to the corresponding standards so maybe this one is more complete.

Community
  • 1
  • 1
SunnyMagadan
  • 1,819
  • 14
  • 12
  • It's worth a try -- I'll see if i can't write a custom matcher to chop that stuff out and report back -- thanks! – Rabbott Aug 04 '16 at 16:10
  • Ruby (rubular) doesn't like the regex you suggested unfortunately, but through a combination of clicks originating with your links above (really helped me with the wording of my search queries) I was able to find `/\e\[\d+m/` as a solid replacement for it. I've included my final solution in an answer -- thanks for your help! – Rabbott Aug 05 '16 at 13:03
  • Sorry, I missed the regex in the beginning of your answer some how, only saw the one at the bottom -- your solution is the regex I was looking for, I've included an answer below that shows my actual implementation of the regex. – Rabbott Aug 05 '16 at 14:12
0

Using @SunnyMagadan's regex /\e\[\d+m/ that successfully locates the colorization. Rather than having to include this in all of my tests, I extended the CliTest Execution class and added a stripped_stdout method that just uses the regex to strip the stdout already defined by the class.

I added this code to a file in /spec/support and imported it in my spec_helper.rb

module CliTest
  class Execution
    # Strips out ansi colorization leaving unformatted text
    def stripped_stdout
      @stdout.gsub(/\e\[\d+m/, '')
    end
  end
end

This allows me to use the following in my tests

expect(last_execution.stripped_stdout).to include("Expected Colorized Output")

Which is a solution I'm happy with. This doesn't disturb any other functionality and allows me to keep using the last_execution.stdout if/when I want to.

Rabbott
  • 4,282
  • 1
  • 30
  • 53