Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failure results make it impossible to figure out what diverged from the expected string #420

Open
kurko opened this issue Dec 9, 2016 · 7 comments

Comments

@kurko
Copy link

kurko commented Dec 9, 2016

Summary

Aruba/Cucumber output is cryptic. It's basically impossible to find out what is different between the expected string and the output string when there's a test failure.

Expected Behavior

I would expect to have something like RSpec provides, like:

expected: "string1"
got:      "string2"

or, because my output has so many \n, make a diff between all of them by splitting lines:

expected: "string1\nstring again"
got:      "string2\nstring again"

-string1\n"
+string2\n"

Current Behavior

The problem is seen in this Pull Request: https://github.com/zipmark/rspec_api_documentation/pull/313/files#diff-0b3146a61839789912f87a2e19beaaa4R244. The library is responsible for generating documentation files. We write an expectation and then make sure the file matches what was generated.

However, when there's one character off, this is the output I get:

expected "FORMAT: A1\n\n# Group Instructions\n\nInstructions help the users use the app.\n\n## Instructions Collection [/instructions]\n\n### Returns all instructions [GET]\n\n+ Request List all instructions\n\n    + Headers\n\n        Host: example.org\n\n    + Body\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 57\n\n+ Response 200 (text/html;charset=utf-8)\n\n    + Headers\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 57\n\n    + Body\n\n        {\"data\":{\"id\":\"1\",\"type\":\"instructions\",\"attributes\":{}}}\n\n# Group Orders\n\nOrders resource\n\n## Orders Collection [/orders]\n\n### Creates an order [POST]\n\n+ Request Creating an order (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 73\n\n+ Response 201 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 73\n\n    + Body\n\n        {\n          \"order\": {\n            \"name\": \"Order 1\",\n            \"amount\": 100.0,\n            \"description\": \"A great order\"\n          }\n        }\n\n### Return all orders [GET]\n\n+ Request Getting a list of orders\n\n    + Headers\n\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 137\n\n+ Response 200 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 137\n\n    + Body\n\n        {\n          \"page\": 1,\n          \"orders\": [\n            {\n              \"name\": \"Order 1\",\n              \"amount\": 9.99,\n              \"description\": null\n            },\n            {\n              \"name\": \"Order 2\",\n              \"amount\": 100.0,\n              \"description\": \"A great order\"\n            }\n          ]\n        }\n\n## Single Order [/orders/{id}]\n\n+ Parameters\n  + id: 1 (required, string) - Order id\n\n+ Attributes (object)\n  + name: a name (required) - The order name\n  + amount - The order amount\n  + description: a description (string) - The order description\n\n### Deletes a specific order [DELETE]\n\n+ Request Deleting an order (application/x-www-form-urlencoded)\n\n    + Headers\n\n        Host: example.org\n        Content-Type: application/x-www-form-urlencoded\n\n    + Body\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 0\n\n+ Response 200 (text/html;charset=utf-8)\n\n    + Headers\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 0\n\n### Returns a single order [GET]\n\n+ Request Getting a specific order\n\n    + Headers\n\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 73\n\n+ Response 200 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 73\n\n    + Body\n\n        {\n          \"order\": {\n            \"name\": \"Order 1\",\n            \"amount\": 100.0,\n            \"description\": \"A great order\"\n          }\n        }\n\n### Updates a single order [PUT]\n\n+ Request Invalid request (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 0\n\n+ Response 400 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 0\n\n+ Request Update an order (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 111\n\n+ Response 200 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 111\n\n    + Body\n\n        {\n          \"data\": {\n            \"id\": \"1\",\n            \"type\": \"order\",\n            \"attributes\": {\n              \"name\": \"Order 1\",\n              \"amount\": 100.0,\n              \"description\": \"A description\"\n            }\n          }\n        }" to have file content: "FORMAT: A1\n\n# Group Instructions\n\nInstructions help the users use the app.\n\n## Instructions Collection [/instructions]\n\n### Returns all instructions [GET]\n\n+ Request List all instructions\n\n    + Headers\n\n        Host: example.org\n\n    + Body\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 57\n\n+ Response 200 (text/html;charset=utf-8)\n\n    + Headers\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 57\n\n    + Body\n\n        {\"data\":{\"id\":\"1\",\"type\":\"instructions\",\"attributes\":{}}}\n\n# Group Orders\n\nOrders resource\n\n## Orders Collection [/orders]\n\n### Creates an order [POST]\n\n+ Request Creating an order (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 73\n\n+ Response 201 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 73\n\n    + Body\n\n        {\n          \"order\": {\n            \"name\": \"Order 1\",\n            \"amount\": 100.0,\n            \"description\": \"A great order\"\n          }\n        }\n\n### Return all orders [GET]\n\n+ Request Getting a list of orders\n\n    + Headers\n\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 137\n\n+ Response 200 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 137\n\n    + Body\n\n        {\n          \"page\": 1,\n          \"orders\": [\n            {\n              \"name\": \"Order 1\",\n              \"amount\": 9.99,\n              \"description\": null\n            },\n            {\n              \"name\": \"Order 2\",\n              \"amount\": 100.0,\n              \"description\": \"A great order\"\n            }\n          ]\n        }\n\n## Single Order [/orders/{id}]\n\n+ Parameters\n  + id: (required, string) - Order id\n\n+ Attributes (object)\n  + name: a name (required) - The order name\n  + amount - The order amount\n  + description: a description (string) - The order description\n\n### Deletes a specific order [DELETE]\n\n+ Request Deleting an order (application/x-www-form-urlencoded)\n\n    + Headers\n\n        Host: example.org\n        Content-Type: application/x-www-form-urlencoded\n\n    + Body\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 0\n\n+ Response 200 (text/html;charset=utf-8)\n\n    + Headers\n\n        Content-Type: text/html;charset=utf-8\n        Content-Length: 0\n\n### Returns a single order [GET]\n\n+ Request Getting a specific order\n\n    + Headers\n\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 73\n\n+ Response 200 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 73\n\n    + Body\n\n        {\n          \"order\": {\n            \"name\": \"Order 1\",\n            \"amount\": 100.0,\n            \"description\": \"A great order\"\n          }\n        }\n\n### Updates a single order [PUT]\n\n+ Request Invalid request (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 0\n\n+ Response 400 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 0\n\n+ Request Update an order (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Host: example.org\n\n    + Body\n\n        Content-Type: application/json\n        Content-Length: 111\n\n+ Response 200 (application/json)\n\n    + Headers\n\n        Content-Type: application/json\n        Content-Length: 111\n\n    + Body\n\n        {\n          \"data\": {\n            \"id\": \"1\",\n            \"type\": \"order\",\n            \"attributes\": {\n              \"name\": \"Order 1\",\n              \"amount\": 100.0,\n              \"description\": \"A description\"\n            }\n          }\n        }" (RSpec::Expectations::ExpectationNotMetError)
      features/api_blueprint_documentation.feature:247:in `Then the file "doc/api/index.apib" should contain exactly:'

Here's an actual print screen:

screen shot 2016-12-09 at 2 56 53 pm

Possible Solution

I tried to dig into Aruba's source code but I'm not very familiar with how even Cucumber works. Its documentation is somewhat cryptic to me (described as steps). I see that there's something called @announce, but that didn't do anything for me (and I failed to find documentation that I could use).

RSpec has that functionality to compare strings built-in. Would it be possible to should pipe that output into RSpec's matches?

I could try to help with that but I'd need directions because the documentation is unclear to me.

Steps to Reproduce (for bugs)

  1. git clone https://github.com/zipmark/rspec_api_documentation.git
  2. git checkout 235-blueprint-api
  3. bundle install
  4. Make a one-character change to features/api_blueprint_documentation.feature, around lines 260.
  5. bundle exec cucumber features

You will see my screenshot, basically.

Context & Motivation

I'm working on a lib that generates documentation automatically based on RSpec tests. The fixture has over 200 lines, so when even one character changes, it's virtually impossible to find out why it's failing, or in other words, what string is different from the expectation.

This is making my work very slow. I have to either look by eye or copy paste somewhere else to figure out the diff.

Your Environment

Thanks a lot.

@mattwynne
Copy link
Member

mattwynne commented Dec 22, 2016

I've experienced the same frustration using aruba in Cucumber-Ruby's own test suite.

The solution, for me, is to use the word 'exactly' in your step, i.e. Then the output should contain exactly). This invokes the exact string matcher meaning you'll get a better diff. Otherwise, it uses a string including matcher, which can't give you as good a diff since it compares using a Regexp.

@maxmeyer
Copy link
Member

maxmeyer commented Apr 7, 2017

@kurko I tried to make output more reable by using the diffable keyword in RSpec matchers:

. If there are more matchers where this does make sense, feel free to provide a pull request.

@maxmeyer maxmeyer added this to the 1.0.0-alpha.3 milestone Jul 31, 2017
@stale
Copy link

stale bot commented Nov 9, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in a week if no further activity occurs.

@stale stale bot added the stale These issues were closed by stalebot and need to be reviewed to see if they're still relevant. label Nov 9, 2017
@stale
Copy link

stale bot commented Nov 16, 2017

This issue has been automatically closed because of inactivity. You can support the Cucumber core team on opencollective.

@stale stale bot closed this as completed Nov 16, 2017
@mvz
Copy link
Contributor

mvz commented Mar 15, 2018

This has been partly handled in #546. For negated matchers, the problem persists.

@mvz mvz reopened this Mar 15, 2018
@stale stale bot removed the stale These issues were closed by stalebot and need to be reviewed to see if they're still relevant. label Mar 15, 2018
@stale
Copy link

stale bot commented May 14, 2018

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in a week if no further activity occurs.

@stale stale bot added the stale These issues were closed by stalebot and need to be reviewed to see if they're still relevant. label May 14, 2018
@xtrasimplicity
Copy link
Member

xtrasimplicity commented May 14, 2018

Bump.

@stale stale bot removed the stale These issues were closed by stalebot and need to be reviewed to see if they're still relevant. label May 14, 2018
@mvz mvz modified the milestones: 1.0.0-alpha.5, 1.1.0 Jan 1, 2020
@mvz mvz modified the milestones: 1.1.0, 1.2.0 Aug 21, 2020
@mvz mvz modified the milestones: 1.2.0, 2.0.0 Jun 20, 2021
@mvz mvz modified the milestones: 2.0.0, 2.1.0 Aug 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants