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

fix slow test for dot reporter #3486

Merged
merged 1 commit into from
Oct 11, 2018

Conversation

outsideris
Copy link
Contributor

Description of the Change

Although there is a slow test case for dot reporter,
coverage is missed.
Since slow duration is 2(slow: function() { return 2; }) and test duration is 2 (test.duration = 2;),
this test is not check slow test actually.

Alternate Designs

N/A

Why should this be in core?

Tests should be run as intended.

@outsideris outsideris added the qa label Sep 25, 2018
@coveralls
Copy link

coveralls commented Sep 25, 2018

Coverage Status

Coverage increased (+0.1%) to 90.429% when pulling 9ec5614 on outsideris:dot-report-slow-test into 04469bf on mochajs:master.

Copy link
Contributor

@plroebuck plroebuck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You changed the test duration, but the test still don't detect "slow"-ness.

Add another assertion after this line that detects color "bright yellow" of dot.

Change PR title to "fix slow test for dot reporter".

@outsideris outsideris changed the title fix slow test properly fot dot reporter fix slow test for dot reporter" Sep 25, 2018
@outsideris
Copy link
Contributor Author

@plroebuck It detected "slow" because duration is 3 and slow is 2.
And it doesn't print bright yellow since this if statement.

@plroebuck
Copy link
Contributor

plroebuck commented Sep 25, 2018

These tests seem hinky to begin with. Why was the test duration ever allowed to be 1? Doubt any of our tests can execute that fast. But after you turn off colors, all passing speeds return a dot. So asserting for a dot can't prove test speed.

  • Should your change apply to all "on pass" tests (L69) and the line you fixed (L100) be removed instead?
  • Should colors be reinstated so test speed can actually be checked?

@outsideris
Copy link
Contributor Author

That's the reason that we didn't find this issue even if this slow test was meaningless.
I got what you point out.

@plroebuck
Copy link
Contributor

Although I applaud your effort in having tracked this down, I see no point in merging this PR in the name of increased coverage - without meaningful changes, it only helps further mask the underlying problems.

@outsideris
Copy link
Contributor Author

  • I turned on useColors since comparing dots without colors is meanless for dot reporter.
  • All tests for dot reporter now assert result with color.

Also, I added a function color() for test purpose. At first, I used Base.color in base.js, but all test still passed if I turn on useColors or not. I want to force to check dot reporter print colors properly.

function color(type, str) {
return '\u001b[' + Base.colors[type] + 'm' + str + '\u001b[0m';
}

Copy link
Contributor

@plroebuck plroebuck Sep 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For simplicity of comparison, it might be easier not to be so literal.

function speedString(type, str) {
  return '##' + type.replace(/ /g, '-') + '_' + str;
};

Base.color = speedString;

@outsideris
Copy link
Contributor Author

I replaced Base.color.

@plroebuck
Copy link
Contributor

plroebuck commented Sep 28, 2018

Come to think of it, given:

if (test.duration > test.slow()) {
  test.speed = 'slow';
} else if (test.duration > test.slow() / 2) {
  test.speed = 'medium';
} else {
  test.speed = 'fast';
}

we could also do this assertion for passing tests.

expect(test.speed, 'to equal', 'fast');

@outsideris
Copy link
Contributor Author

However, they are not only for speed test. We should check report type, dot in here.

expect(stdout, 'to equal', expectedArray);
});
});
});
describe('if window width is equal to or less than 1', function() {
describe('if test speed is fast', function() {
it('should return a dot', function() {
it('should return a grey dot', function() {
runner = createMockRunner('pass', 'pass', null, null, test);
Dot.call({epilogue: function() {}}, runner);
process.stdout.write = stdoutWrite;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

          expect(test.speed, 'to equal', 'fast');

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you mean and why we check only speed.

Copy link
Contributor

@plroebuck plroebuck Sep 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the field is set for pass events by runner in Base ctor; it's the only field set there.
test.speed assertions are in addition to your stdout assertions, not in lieu of them.
they should agree though.

@@ -80,28 +86,38 @@ describe('Dot reporter', function() {
runner = createMockRunner('pass', 'pass', null, null, test);
Dot.call({epilogue: function() {}}, runner);
process.stdout.write = stdoutWrite;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

          expect(test.speed, 'to equal', 'fast');

describe('if test speed is slow', function() {
it('should return a dot', function() {
describe('if test speed is medium', function() {
it('should return a yellow dot', function() {
test.duration = 2;
runner = createMockRunner('pass', 'pass', null, null, test);
Dot.call({epilogue: function() {}}, runner);
process.stdout.write = stdoutWrite;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

          expect(test.speed, 'to equal', 'medium');

test.duration = 3;
runner = createMockRunner('pass', 'pass', null, null, test);
Dot.call({epilogue: function() {}}, runner);
process.stdout.write = stdoutWrite;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

          expect(test.speed, 'to equal', 'slow');

@@ -50,7 +56,7 @@ describe('Dot reporter', function() {
runner = createMockRunner('pending', 'pending');
Dot.call({epilogue: function() {}}, runner);
process.stdout.write = stdoutWrite;
Copy link
Contributor

@plroebuck plroebuck Sep 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're doing stream reassignment after Dot.call(), why repeat in afterEach()?
And we should explain why it's being done within test, rather than afterwards.

function runReporter(stubSelf, runner) {
  // Reassign stream in order to make a copy of all reporter output
  var stdoutWrite = process.stdout.write;
  process.stdout.write = function(string, enc, callback) {
    stdout.push(string);
    stdoutWrite.call(process.stdout, string, enc, callback);
  };

  // Invoke reporter
  Dot.call(stubSelf, runner);

  // Revert stream reassignment here so reporter output
  // can't be corrupted if any test assertions throw
  process.stdout.write = stdoutWrite;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will test what you provide.

});

afterEach(function() {
Base.useColors = useColors;
Base.window.width = windowWidth;
Base.color = color;
process.stdout.write = stdoutWrite;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runner = undefined;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean that reset runner here before every test?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. runner recreated per-test. reset ensures you can't forget to do so.

@outsideris
Copy link
Contributor Author

I fixed them.

beforeEach(function() {
stdout = [];
stdoutWrite = process.stdout.write;
function runReporter(stubSelf, runner) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  function runReporter(stubSelf, runner, tee) {

stdoutWrite = process.stdout.write;
function runReporter(stubSelf, runner) {
// Reassign stream in order to make a copy of all reporter output
var stdoutWrite = process.stdout.write;
process.stdout.write = function(string, enc, callback) {
stdout.push(string);
stdoutWrite.call(process.stdout, string, enc, callback);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    if (tee) {
      stdoutWrite.call(process.stdout, string, enc, callback);
    }

@@ -8,35 +8,50 @@ var createMockRunner = require('./helpers.js').createMockRunner;

describe('Dot reporter', function() {
var stdout;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  var showOutput = false;

});

describe('on start', function() {
it('should return a new line', function() {
runner = createMockRunner('start', 'start');
Dot.call({epilogue: function() {}}, runner);
process.stdout.write = stdoutWrite;
runReporter({epilogue: function() {}}, runner);
Copy link
Contributor

@plroebuck plroebuck Oct 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add showOutput argument to all runReporter invocations that follow.

     runReporter({epilogue: function() {}}, runner, showOutput);

@plroebuck
Copy link
Contributor

It looked good. But glancing job results on Travis, wondered why we would be displaying the test output (which intermixes with the job "spec" report).

So my final requested modification:

  • Add argument tee to runReport function
  • Add a describe()-level global showOutput which defaults to false
  • Make all invocations of runReport add showOutput as final parameter.

Now, debugging a test is still simple, but output is turned off by default.

var runner;
var useColors;
var windowWidth;
var color;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  /**
   * Run reporter using stream reassignment to capture output.
   *
   * @param {Object} stubSelf - Reporter-like stub instance
   * @param {Runner} runner - Mock instance
   * @param {boolean} [tee=false] - If `true`, echo captured output to screen
   */

@outsideris outsideris changed the title fix slow test for dot reporter" fix slow test for dot reporter Oct 3, 2018
@outsideris
Copy link
Contributor Author

Now, debugging a test is still simple, but output is turned off by default.

It is a good idea.
We can apply this idea to other reporter tests. Modification for other reporters is in another PR is better.

});

afterEach(function() {
Base.useColors = useColors;
Base.window.width = windowWidth;
process.stdout.write = stdoutWrite;
Base.color = color;
runner = undefined;
});

describe('on start', function() {
it('should return a new line', function() {
Copy link
Contributor

@plroebuck plroebuck Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a newline"

@@ -48,18 +73,16 @@ describe('Dot reporter', function() {
});
it('should return a new line and then a coma', function() {
Copy link
Contributor

@plroebuck plroebuck Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a newline followed by a comma"

process.stdout.write = stdoutWrite;
var expectedArray = ['\n ', Base.symbols.comma];
runReporter({epilogue: function() {}}, runner, showOutput);
var expectedArray = ['\n ', 'pending_' + Base.symbols.comma];
expect(stdout, 'to equal', expectedArray);
});
});
describe('if window width is equal to or less than 1', function() {
it('should return a coma', function() {
Copy link
Contributor

@plroebuck plroebuck Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a comma"

@@ -78,30 +101,40 @@ describe('Dot reporter', function() {
describe('if test speed is fast', function() {
it('should return a new line and then a dot', function() {
Copy link
Contributor

@plroebuck plroebuck Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a newline followed by a dot"

@@ -119,18 +152,16 @@ describe('Dot reporter', function() {
});
it('should return a new line and then an exclamation mark', function() {
Copy link
Contributor

@plroebuck plroebuck Oct 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a newline followed by an exclamation mark"

expect(stdout, 'to equal', expectedArray);
});
});
});
describe('if window width is equal to or less than 1', function() {
describe('if test speed is fast', function() {
it('should return a dot', function() {
it('should return a grey dot', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a grey dot"

describe('if test speed is slow', function() {
it('should return a dot', function() {
describe('if test speed is medium', function() {
it('should return a yellow dot', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a yellow dot"

});
});
describe('if test speed is slow', function() {
it('should return a bright yellow dot', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write a bright yellow dot"

process.stdout.write = stdoutWrite;
var expectedArray = ['\n ', Base.symbols.bang];
runReporter({epilogue: function() {}}, runner, showOutput);
var expectedArray = ['\n ', 'fail_' + Base.symbols.bang];
expect(stdout, 'to equal', expectedArray);
});
});
describe('if window width is equal to or less than 1', function() {
it('should return an exclamation mark', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"should write an exclamation mark"

@outsideris
Copy link
Contributor Author

I updated the test names.

Copy link
Contributor

@plroebuck plroebuck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. I think the Dot reporter test specification is now an example to be emulated by the others. Sorry about the constant flow of changes, but after each iteration different things stood out.

Thanks for taking the time to get this fixed properly!

Labels: reporter, semver-patch.
LGTM!

@plroebuck
Copy link
Contributor

On the other hand, I am starting to rethink the design of some of the code in the Base reporter. Think many of these standalone exports (e.g., Base.color()) should have been subclass instance properties/methods rather than module exports. Assuming a goal of being able to have multiple reporters for a Mocha execution, this would need change to prevent one reporter from (even inadvertently) affecting any others. For example, Dot.colors.slow = 'bright yellow'; in its ctor would have eliminated the if condition within the onPassCB event handler.

@outsideris
Copy link
Contributor Author

For example, Dot.colors.slow = 'bright yellow'; in its ctor would have eliminated the if condition within the onPassCB event handler.

what ctor means?

@outsideris
Copy link
Contributor Author

I will merge this if one more core members approved.

@outsideris outsideris added area: reporters involving a specific reporter semver-patch implementation requires increase of "patch" version number; "bug fixes" labels Oct 8, 2018
@plroebuck
Copy link
Contributor

@outsideris ctor

@outsideris
Copy link
Contributor Author

I see. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: reporters involving a specific reporter semver-patch implementation requires increase of "patch" version number; "bug fixes"
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants