Skip to content

test: switch to AVA#512

Closed
ariporad wants to merge 16 commits intomasterfrom
codemods
Closed

test: switch to AVA#512
ariporad wants to merge 16 commits intomasterfrom
codemods

Conversation

@ariporad
Copy link
Copy Markdown
Contributor

@ariporad ariporad commented Aug 26, 2016

This PR switches our tests to AVA. It's very much still a work in progress.

Because switching to a whole new testing framework is a very large task, this was all done with a codemod (basically, a babel plugin which re-writes our tests. It's in the codemods folder if you're interested). Immediately after running the codemod, ~2/3 of our tests passed with AVA. (Which is pretty good). The rest are going to have to be fixed by hand (still waaay faster than doing it all manually).

I'll be continually updating this PR as I fix more of the tests.

I'm opening this PR so early in the process because:

  1. I want other people to be aware of it, and
  2. I'd like to get as many eyes on the changes as possible, to correct any errors.

Things which need to get done:

  • Run the codemod.
  • Add ava to package.json as a devDependency and as the npm run test script.
  • Fix all the tests on unix
  • Separate out tests that were merged together as part of the refactoring (look for @@TEST)
  • Fix lint errors
  • Fix all the tests on Windows (some tests need to be skipped or modified, like chmod)
  • Remove useless tests (that were a result of refactoring errors)
  • Make sure all tests have useful and descriptive names
  • Refactor all tests to run in their own isolated temp directory
  • Properly parallelize all the tests
  • Delete the codemod files
  • Verify that we didn't remove any tests (this is probably a file-by-file process)
  • Make sure tests aren't flaky
  • Fix all TODOs

@nfischer
Copy link
Copy Markdown
Member

Saw this, looks pretty good! Here's some initial questions:

  1. Can we add some beforeEach steps to the tests to make sure they all start in a standardized wishing directory, with the same contents in the test directory, etc?
  2. I noticed that you unwrapped the callbacks in echo. Doesn't this mean that those test cases will report success before actually calling the callbacks (which is where the real test is)? Is there any way to prevent that from happening?
  3. I saw that the tests were in es6. Will Ava take care of the translation? It may be worth it to write the tests in es 5 if it cuts down on deps.

@nfischer
Copy link
Copy Markdown
Member

nfischer commented Aug 26, 2016

@ariporad all tests should be working for sync, but we'll need to refactor plugin.js for async. Here's what I want to do (in mocha syntax, since that's what I'm familiar with):

describe('before doing plugin', () => {
  it('does not exist before being registered', () => {
    t.is(!shell.foo);
  });
});
describe('before doing plugin', () => {
  beforeEach(() => {
    plugin.register('foo', fooImplementation, {
      cmdOptions: {
        'f': 'flag',
      },
      wrapOutput: true,
      canReceivePipe: true,
    });
  });

  afterEach(() => {
    // do something to un-register the plugin
  });

  it('exists after registering', () => {
    t.is(shell.foo);
  });
});

I'm not sure what the equivalent of describe is in ava, but basically I need a way to make sure the plugin is not registered before some of the tests, and is registered before some other tests, so I need a different beforeEach() step depending on the test.

test/dirs.js Outdated

test('Clearing items', t => {
t.deepEqual(shell.dirs('-c'), []);
assert(!shell.error());
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oops... I forgot to fix this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No worries, it should be resolved now. Simple regex 😄

@ariporad
Copy link
Copy Markdown
Contributor Author

@nfischer: Wow... you did a lot!

Your questions, in order:

  1. We could.
  2. We'd need to use test.cb.
  3. AVA automagically babels the tests, but not the source.
  4. You'd need a seperate test file, there is no describe in AVA.

I'm going to be busy till tomorrow morning, but I'll try to review everything then.

@nfischer
Copy link
Copy Markdown
Member

@ariporad would we be able to serialize the tests within plugin.js (once everything else is parallel by default)? It seems like test.serial() would work for us, but I'm not sure if we only need to put it on the first test case or if we need to put it on all the test cases in that file.

@nfischer
Copy link
Copy Markdown
Member

@ariporad I'll leave the rest of this to you, since there shouldn't be much more. Ping me on here when it's ready for review 😄

@ariporad
Copy link
Copy Markdown
Contributor Author

@nfischer: Ok, this should be good now, it all passes lint. I don't have a way to test on windows, but otherwise should be good.

@nfischer
Copy link
Copy Markdown
Member

@ariporad the tests are failing because we used to skip some tests when running on Windows (chmod was notorious for that). If you check master branch, you'll see which test cases to skip. Probably the best way I can think of is:

test('title', t => {
  if (windows) return;
  // otherwise proceed as normal
});

Copy link
Copy Markdown
Member

@nfischer nfischer left a comment

Choose a reason for hiding this comment

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

@ariporad I left some initial comments

test/which.js Outdated

if (process.platform === 'win32') {
// TODO: Why are we skipping this?
windows.skip('No Test Title #60', t => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is incorrect. This test only works on Windows, not Unix. You're skipping on Windows and running it on Unix.

test/which.js Outdated
}

shell.exit(123);
t.is(node + '', nodeExe + '');
Copy link
Copy Markdown
Member

@nfischer nfischer Sep 26, 2016

Choose a reason for hiding this comment

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

Could you change this to node.toString() and nodeExe.toString()? I think that would make the meaning more clear. A simple regex should catch all occurrences of this.

test/cp.js Outdated
test('dest already exists', t => {
const oldContents = shell.cat('resources/file2').toString();
const result = shell.cp('-n', 'resources/file1', 'resources/file2'); // dest already exists
t.truthy(!shell.error());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we convert t.truthy(!expr); to t.falsy(expr);? It should be a bit more readable.

test/exec.js Outdated
t.is(result.stderr, '');
});

test.todo('set shell option for windows');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is this?

test/exec.js Outdated
test.cb('callback as 2nd argument', t => {
shell.exec(JSON.stringify(process.execPath) + ' -e "console.log(5678);"', function (code, stdout, stderr) {
t.is(code, 0);
t.truthy(stdout === '5678\n');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you change this to t.is(stdout, '5678\n');?

test/exec.js Outdated
shell.exec(JSON.stringify(process.execPath) + ' -e "console.log(5678);"', function (code, stdout, stderr) {
t.is(code, 0);
t.truthy(stdout === '5678\n');
t.truthy(stderr === '');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Save comment as above

test/exec.js Outdated
});
t.is(code2, 0);
t.truthy(stdout2 === '5566\n');
t.truthy(stderr2 === '');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same comments as above

test/exec.js Outdated
shell.exec(JSON.stringify(process.execPath) + ' -e "console.log(5678);"', { silent: true }, function (code3, stdout3, stderr3) {
t.is(code3, 0);
t.truthy(stdout3 === '5678\n' || stdout3 === '5678\nundefined\n'); // 'undefined' for v0.4
t.truthy(stderr3 === '' || stderr3 === 'undefined\n'); // 'undefined' for v0.4
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same comments as above

@nfischer
Copy link
Copy Markdown
Member

@ariporad are we still working on this? If so, would you be able to rebase this off master?

@nfischer nfischer force-pushed the codemods branch 2 times, most recently from 31a96f3 to b9c37ab Compare November 1, 2016 07:37
@nfischer
Copy link
Copy Markdown
Member

nfischer commented Nov 1, 2016

@freitagbr (and any one else), feel free to help take this on. Tests are still very flaky when run in parallel mode.

@nfischer
Copy link
Copy Markdown
Member

nfischer commented Nov 1, 2016

Also, here's a running list of the files I've verified have not lost any test cases during the refactor:

  • cat.js
  • cd.js
  • chmod.js
  • common.js
  • config.js
  • cp.js
  • dirs.js
  • echo.js
  • env.js
  • exec.js
  • find.js
  • global.js
  • grep.js
  • head.js
  • ln.js
  • ls.js
  • mkdir.js
  • mv.js
  • pipe.js
  • plugin.js
  • popd.js
  • pushd.js
  • pwd.js
  • rm.js
  • sed.js
  • set.js
  • shjs.js
  • sort.js
  • tail.js
  • tempdir.js
  • test.js
  • toEnd.js
  • to.js
  • touch.js
  • uniq.js
  • which.js

@freitagbr
Copy link
Copy Markdown
Contributor

I think I know why the tests are failing. Let's look at grep.js for example:

let TMP;

test.beforeEach(() => {
  TMP = utils.getTempDir();
  shell.config.silent = true;
  shell.cp('-r', 'resources', TMP);
});

Isn't the value of TMP going to be overwritten with every test? So one of the grep tests is looking to see if the TMP exists, but the value of TMP intended for that test has already been overwritten by the value of TMP for another test.

In other words, we can't have any globals in these async tests. That, or we keep a stack or something of all the tmp directories that get created.

@freitagbr
Copy link
Copy Markdown
Contributor

Solution to the problem, do something like this:

test.beforeEach(t => {
  const tmp = t.context.tmp = utils.getTempDir();
  shell.config.silent = true;
  shell.cp('-r', 'resources', tmp);
});

test('example' t => {
    // t.context.tmp is the tmp dir for this test
});

@nfischer
Copy link
Copy Markdown
Member

nfischer commented Nov 2, 2016

@freitagbr ah, that looks perfect. That's just what I was looking for. I'll do the refactor tonight and push again

@freitagbr
Copy link
Copy Markdown
Contributor

@nfischer I already wrote the code to test it. Can I submit a PR to this branch?

@freitagbr
Copy link
Copy Markdown
Contributor

Even after fixing that bug, I still get an error:

> ava test/*.js

   451 passed
   1 failed

   1. tail › reading more lines than are in the file (no trailing newline)

  t.is(result.toString(), 'test2\ntest1')
              |
              "test1\ntest1"

      "test1/ntest1"
        Test.fn (tail.js:74:5)
        _combinedTickCallback (internal/process/next_tick.js:67:7)
        process._tickCallback (internal/process/next_tick.js:98:9)

@nfischer
Copy link
Copy Markdown
Member

nfischer commented Nov 2, 2016

@freitagbr whoops, didn't see your comment. Take a look at the commit I just uploaded here. If I missed anything, feel free to correct it

@nfischer nfischer changed the title [WIP] chore: switch to AVA test: switch to AVA Nov 8, 2016
@nfischer
Copy link
Copy Markdown
Member

Alright. Since we're starting to get merge conflicts with other patches that are going through, and I'm tired of rebasing, I think we should start merging these files one at a time. Here's the proposed strategy to do this in a sane way:

  • make a directory called ava-test/
  • copy the resources to ava-test/resources/ (leave a copy where it is now, too)
  • one by one, remove a file from test/ and put its ava equivalent in ava-test/
  • modify npm test: instead of node scripts/run-tests, turn it into node scripts/run-tests && ava --serial ava-test/*.js

Once all tests are refactored like this, we just do rm -rf test/ && git mv ava-test test.

@freitagbr what are your thoughts on this plan?

@freitagbr
Copy link
Copy Markdown
Contributor

I think that's a good plan. Just keep an eye community contributions, they might get confused as to where their tests should go.

@nfischer
Copy link
Copy Markdown
Member

Closing this, since we're almost done migrating all the tests

@nfischer nfischer closed this Dec 20, 2016
@nfischer nfischer deleted the codemods branch December 20, 2016 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants