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

Better string and object diffs #406

Closed
jamestalmage opened this issue Jan 4, 2016 · 24 comments
Closed

Better string and object diffs #406

jamestalmage opened this issue Jan 4, 2016 · 24 comments

Comments

@jamestalmage
Copy link
Contributor

The power-assert output is great except for long strings and moderate to large sized JSON objects.

I think for those cases, it is probably better to just output a diff. Something similar to mocha.

(I'm almost certain there was an issue raised about this already, but I couldn't find it quickly).

@sindresorhus
Copy link
Member

Hah, opening an issue like this was already on my todo list. 👍 👍

Is this maybe something the power-assert reporter should handle?

@TrySound
Copy link
Contributor

TrySound commented Jan 4, 2016

Related power-assert-js/power-assert#31

@jamestalmage
Copy link
Contributor Author

Hmm. I don't know. It doesn't depend on powerAssertContext at all, just assertionErrror.expected and assertionError.actual, it certainly could be implemented as a custom reporter. I just don't know if that's the best choice.

// @twada

@twada
Copy link
Contributor

twada commented Jan 4, 2016

It doesn't depend on powerAssertContext at all, just assertionErrror.expected and assertionError.actual

It makes sense when the assertion has two args (t.is, t.not, t.same, t.notSame).
With one arg (t.ok, t.notOk), power-assert should handle string diff and that's what BinaryExpressionRenderer does.

Rendering diffs between expected and actual could be handled by power-assert, and I'm thinking about implementing it though.

@jamestalmage
Copy link
Contributor Author

Oh yeah, forgot about BinaryExpressionRenderer - we definitely want good diffs if they do:

t.true(someLongString === someOtherLongString)

How about extending BinaryExpressionRenderer with a "minimumLength" parameter that prevents short diffs from being displayed, a diff for t.true("foo" === "bar") is unnecessarily verbose, and it's easy to spot the difference looking at the power assert graph output.

@sindresorhus
Copy link
Member

From Gitter, for posterity:

jamestalmage
@ben-eb power-asserts BinaryExpressionRenderer will output pretty diffs. So it would just be a matter of adding that in enhance.js.

ben-eb
@jamestalmage here? https://github.com/sindresorhus/ava/blob/master/lib/enhance-assert.js#L47-L52

jamestalmage 01:05
@ben-eb See the discussion in that PR. We don’t want BinaryExpressionRenderer to always show a diff. It’s too verbose.

ben-eb 01:06
i wouldn't either, no

jamestalmage 01:06
yep - that’s where.
I think the difficulty in fixing this is figuring out how to decide when to enable the BinaryExpressionRenderer.

ben-eb 01:07
so, is it possible to set a length at where diffs would render?
right

jamestalmage 01:08
It’s not possible in BinaryExpressionRenderer itself, but if you make a good PR that is general use (i.e. not exclusively targeted towards AVA). @twada will accept it. Our other option is to just wrap the renderer and delegate to it only if certain conditions are met.
I’m not sure if it’s as simple as string.length. It may be. Or you may need to examine the AST that is available in powerAssertContext that gets passed to the renderer.

ben-eb 01:10
what about this option? https://www.npmjs.com/package/power-assert-formatter#optionslinediffthreshold

jamestalmage 01:12
Yep - that looks key. Note that we don’t use that module. But build a formatter from individual renderers.
err - I’m wrong on that.

ben-eb 01:13
was going to say it's required in that file 😄

jamestalmage 01:14
We only use two of these five renderers
This may be doable with existing power-assert options.

ben-eb 01:18
think my only issue is that my string diffs don't have newlines, so I would want to be able to test against the length instead of the number of lines 😄

ben-eb 01:40
i didn't read that documentation properly, says it supports character level for lineDiffThreshold

ben-eb 03:17
sorry james, i'm completely lost with this.
i don't even know how i can break AVA's default assertions so that i can always show a diff

@twada
Copy link
Contributor

twada commented Feb 9, 2016

@sindresorhus Oh thanks

@ben-eb
Copy link
Contributor

ben-eb commented Feb 9, 2016

I'd love this feature by the way, but I'm not at all familiar with AVA's code base...

@paulyoung
Copy link

As a workaround I've been doing this:

export const same = (t, actual, expected, message) => {
  return t.same(actual, expected, `

    ${message}

    Actual:
    ${JSON.stringify(actual, null, 2).split("\n").join("\n    ")}

    Expected:
    ${JSON.stringify(expected, null, 2).split("\n").join("\n    ")}

  `);
};

and then using:

same(t, actual, expected, message);

instead of:

t.same(actual, expected, message);

@vadimdemedes
Copy link
Contributor

@paulyoung Good trick!

@novemberborn
Copy link
Member

I've run into this lately. It makes it getting tests to pass quite cumbersome. Maybe we should step up the priority?

@twada are you saying this should be fixed in power-assert-renderers? Is it this issue: twada/power-assert-renderers#1? What can we do to help?

@twada
Copy link
Contributor

twada commented Apr 6, 2016

@novemberborn I've started a new power-assert-runtime modules in a monorepo style and deprecate power-assert-renderers.

First alpha version is already published and the first beta version will be released soon, maybe this weekend.

@twada are you saying this should be fixed in power-assert-renderers? Is it this issue: twada/power-assert-renderers#1? What can we do to help?

Therefore, this issue would be fixed in new power-assert-runtime repo. I'll migrate power-assert-renderers issues to power-assert-runtime.

Sorry for inconvenience 🙇 Let's go forward together.

@novemberborn
Copy link
Member

@twada cool, I just started watching the new repo 😄

@MoOx
Copy link

MoOx commented Apr 8, 2016

I have to admit that long multilines string can be a pain

  ✖ Button render a MaterialUI <FlatButton />   
  t.deepEqual(actual, expected)
              |       |        
              |       "<FlatButton\n  backgroundColor=\"transparent\"\n  disabled={false}\n  hoverColor={{values: {alpha: 1, cmyk: [0, 0, 0, 7], hsl: [0, 0, 93], hsv: [0, 0, 93], hwb: [0, 93, 7], rgb: [238, 238, 238]}}}\n  label=\"Click\"\n  labelPosition=\"after\"\n  labelStyle={{color: {values: {alpha: 1, cmyk: [100, 56, 0, 45], hsl: [214, 100, 28], hsv: [214, 100, 55], hwb: [214, 0, 45], rgb: [0, 62, 141]}}}}\n  onKeyboardFocus={function noRefCheck() {}}\n  onMouseDown={function noRefCheck() {}}\n  onMouseEnter={function noRefCheck() {}}\n  onMouseLeave={function noRefCheck() {}}\n  onMouseUp={function noRefCheck() {}}\n  onTouchEnd={function noRefCheck() {}}\n  onTouchStart={function noRefCheck() {}}\n  primary={false}\n  rippleColor={{values: {alpha: 1, cmyk: [0, 0, 0, 39], hsl: [0, 0, 61], hsv: [0, 0, 61], hwb: [0, 61, 39], rgb: [155, 155, 155]}}}\n  secondary={false}\n  style={{}}\n/>"
              "<FlatButton\n  backgroundColor=\"transparent\"\n  disabled={false}\n  hoverColor=\"rgb(238, 238, 238)\"\n  label=\"Click\"\n  labelPosition=\"after\"\n  labelStyle={{color: 'rgb(0, 62, 141)'}}\n  onKeyboardFocus={function noRefCheck() {}}\n  onMouseDown={function noRefCheck() {}}\n  onMouseEnter={function noRefCheck() {}}\n  onMouseLeave={function noRefCheck() {}}\n  onMouseUp={function noRefCheck() {}}\n  onTouchEnd={function noRefCheck() {}}\n  onTouchStart={function noRefCheck() {}}\n  primary={false}\n  rippleColor=\"rgb(155, 155, 155)\"\n  secondary={false}\n  style={{}}\n/>"


  1 test failed

  1. Button render a MaterialUI <FlatButton />
  AssertionError: '<FlatButton\n  backgroundColor="transparent"\n  disabled={false}\n  hoverColor="rgb(238, 238, 238)"\n  label="Click"\n  labelPo === '<FlatButton\n  backgroundColor="transparent"\n  disabled={false}\n  hoverColor={{values: {alpha: 1, cmyk: [0, 0, 0, 7], hsl: [0
    Test.fn (index.js:39:5)

And in the terminal, it's even worst because you cannot scroll horizontally :)

@wenzowski
Copy link

Doing something similar to @paulyoung

import chalk from 'chalk';
import * as JsDiff from 'diff';

// warning!
// t.deepEqual() tests attribute order while prettyDiff() does not
export function deepEqual(t, actual, expected) {
  t.deepEqual(actual, expected, prettyDiff(actual, expected));
}

export function prettyDiff(actual, expected) {
  const diff = JsDiff.diffJson(expected, actual).map(part => {
    if (part.added) return chalk.green(part.value.replace(/.+/g, '    - $&'));
    if (part.removed) return chalk.red(part.value.replace(/.+/g, '    + $&'));
    return chalk.gray(part.value.replace(/.+/g, '    | $&'));
  }).join('');
  return `\n${diff}\n`;
}

diff 2.2.2
chalk 1.1.3

@Whoaa512
Copy link

Also something similar to @wenzowski and @paulyoung but with less moving parts:

import difflet from 'difflet'

const diff = difflet({ indent: 2 })

export default function deepEqual(t, actual, expected) {
    t.deepEqual(actual, expected, diff.compare(actual, expected))
}

difflet@1.0.1

@calebmer
Copy link

Is anyone working on this?

@sotojuan
Copy link
Contributor

@calebmer I don't think so, want to help?

@iamstarkov
Copy link
Contributor

@sotojuan what was the last idea to fix this?

@creeperyang
Copy link

creeperyang commented Jan 19, 2017

SO no one is working on this?

Long string diff is really hard to read with ava@0.17.

Just a pic:

2017-01-19 4 36 43

@sindresorhus
Copy link
Member

@creeperyang It's being worked on in #1154.

@creeperyang
Copy link

Great! 👍

@hughrawlinson
Copy link

#1154 is merged! Is this issue closeable now? Or are you waiting for the release?

@novemberborn
Copy link
Member

@hughrawlinson that's in the release, so yup, this issue can be closed. Thanks for reminding us.

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