activationHooks break unit tests


#1

Hi!

When I add activationHooks to a package, activating the package in the unit tests starts failing.

What should I do in beforeEach() (or wherever) to make the unit tests pass again?

Manually following the steps in the spec shows that the package works as intended, AFAICT it’s only the tests that are broken.

I’ve tried and failed at lots of things now, help would be appreciated!

Repro:

  1. git clone git@github.com:walles/linter-js-yaml.git
  2. cd linter-js-yaml
  3. git checkout activationhooks
  4. apm install
  5. npm test

Current result:

~/s/atom-linter-js-yaml ((activationhooks)|✔) $ npm test

> linter-js-yaml@1.2.5 test /Users/walles/src/atom-linter-js-yaml
> apm test

FFF

Js-YAML provider for Linter
  it finds something wrong with bad.yaml
    timeout: timed out after 5000 msec waiting for promise to be resolved or rejected
  it finds nothing wrong with issue-2.yaml.
    timeout: timed out after 5000 msec waiting for promise to be resolved or rejected
  it finds nothing wrong with issue-9.yaml.
    timeout: timed out after 5000 msec waiting for promise to be resolved or rejected


Finished in 15.043 seconds
3 tests, 3 assertions, 3 failures, 0 skipped

Tests failed
npm ERR! Test failed.  See above for more details.

Expected result:

~/s/atom-linter-js-yaml ((activationhooks)|✔) $ npm test

> linter-js-yaml@1.2.5 test /Users/walles/src/atom-linter-js-yaml
> apm test

...

Finished in 0.178 seconds
3 tests, 7 assertions, 0 failures, 0 skipped

Tests passed

Notes

If I remove the activationHooks line from package.json, the tests pass again.

Help!


#2

I don’t see you activating the language-yaml package. Hard for the grammar to be used if the grammar doesn’t exist :grinning: In order to make tests run as quickly as possible, Atom doesn’t activate any packages for you in tests. If your test needs a package to be activated, you have to do it.


#3

OK, so I now do this and get the same result:

  beforeEach(() => {
    waitsForPromise(() =>
      atom.packages.activatePackage('language-yaml')
    );

    waitsForPromise(() =>
      atom.packages.activatePackage('linter-js-yaml').then(() =>
        atom.config.set('linter-js-yaml.customTags', ['!yaml', '!include'])
      )
    );
  });

I’m sorry if these questions are silly, I have unsuccessfully searched for docs or examples.

More help?

This is with Atom 1.12.2 btw.


#4

Full source here BTW, WIP in activationhooks2 branch:

Not allowed to post the link as a link, sorry about that…


#5

Do you know which promise is making the tests time out? I suspect by waiting for the promise of the linter-js-yaml package in the beforeEach, you’re breaking the test before the test even gets run. Here’s my theory:

  1. Call activatePackage on language-yaml and wait for promise
  2. Call activatePackage on linter-js-yaml and wait for promise

But activatePackage for linter-js-yaml just returns a promise that doesn’t resolve until a file is opened using the YAML grammar. But because you’re waiting for the promise to resolve before exiting the beforeEach, you’ve got a deadlock.


#6

Now I have this, added loading a YAML file as well, still doesn’t work:

  beforeEach(() => {
    waitsForPromise(() =>
      atom.packages.activatePackage('language-yaml').then(() =>
        console.log('language activated'))
    );

    waitsForPromise(() =>
      atom.workspace.open(travisYml).then(() =>
        console.log('file opened'))
    );

    waitsForPromise(() =>
      atom.packages.activatePackage('linter-js-yaml').then(() => {
        console.log('linter-js-yaml activated');
        atom.config.set('linter-js-yaml.customTags', ['!yaml', '!include']);
      })
    );

It’s the linter-js-yaml promise that times out.

The updated code is in the activationhooks2 branch.


#7

I would try debugging it then to see where it chokes.


#8

It’s the linter-js-yaml promise in beforeEach that times out.

How can I get it to not time out?

I have tried both to find docs and examples on how to do this, and experimented quite a lot, an I’m really at a loss here :(.

Full output:

~/s/atom-linter-js-yaml (activationhooks2|✚1) $ npm test

> linter-js-yaml@1.2.5 test /Users/johan/src/atom-linter-js-yaml
> apm test

[25127:1117/212801:INFO:CONSOLE(20)] "language activated", source: /Users/johan/src/atom-linter-js-yaml/spec/linter-spec.js (20)
[25127:1117/212801:INFO:CONSOLE(26)] "file opened", source: /Users/johan/src/atom-linter-js-yaml/spec/linter-spec.js (26)
F[25127:1117/212806:INFO:CONSOLE(20)] "language activated", source: /Users/johan/src/atom-linter-js-yaml/spec/linter-spec.js (20)
[25127:1117/212806:INFO:CONSOLE(26)] "file opened", source: /Users/johan/src/atom-linter-js-yaml/spec/linter-spec.js (26)
F[25127:1117/212811:INFO:CONSOLE(20)] "language activated", source: /Users/johan/src/atom-linter-js-yaml/spec/linter-spec.js (20)
[25127:1117/212811:INFO:CONSOLE(26)] "file opened", source: /Users/johan/src/atom-linter-js-yaml/spec/linter-spec.js (26)
F

Js-YAML provider for Linter
  it finds something wrong with bad.yaml
    timeout: timed out after 5000 msec waiting for promise to be resolved or rejected
  it finds nothing wrong with issue-2.yaml.
    timeout: timed out after 5000 msec waiting for promise to be resolved or rejected
  it finds nothing wrong with issue-9.yaml.
    timeout: timed out after 5000 msec waiting for promise to be resolved or rejected


Finished in 15.148 seconds
3 tests, 3 assertions, 3 failures, 0 skipped

Tests failed
npm ERR! Test failed.  See above for more details.

#9

Have you tried running the specs through the UI and using a debug breakpoint to step through the code?


#10

I finally found a working example and now it works:

https://github.com/AtomLinter/linter-js-yaml/pull/99/files

Could you look into having this documented better? Having to call atom.packages.triggerDeferredActivationHooks() was really non-obvious…

Here’s what works:

  beforeEach(() => {
    // This whole beforeEach function is inspired by:
    // https://github.com/AtomLinter/linter-jscs/pull/295/files
    //
    // See also:
    // https://discuss.atom.io/t/activationhooks-break-unit-tests/36028/8
    const activationPromise = atom.packages.activatePackage('linter-js-yaml').then(() =>
      atom.config.set('linter-js-yaml.customTags', ['!yaml', '!include'])
    );

    waitsForPromise(() =>
      atom.packages.activatePackage('language-yaml'));

    waitsForPromise(() =>
      atom.workspace.open(travisYml));

    atom.packages.triggerDeferredActivationHooks();
    waitsForPromise(() => activationPromise);
  });

#11

Do you have a suggestion of where and how to document it best? Perhaps you could submit a PR?


#12

Actually, currently this shouldn’t be documented, as it isn’t a public method. On the other hand… it’s impossible to write specs without it.

Is there any way we could get atom.packages.triggerDeferredActivationHooks() moved to the public API @leedohm?


#13

Unfortunately I don’t understand why the solution works, so I don’t feel qualified to explain it.

A good place for this information might be a new chapter on writing linters here:
http://flight-manual.atom.io/hacking-atom/


#14

As mentioned on Slack, yes, I’m :thumbsup: on that.