Need help with writing specs around package activation


#1

I’m trying to do this from Learning Tests using Jasmine, and running into trouble. Since I don’t know what’s synchronous and asynchronous, I’m getting unrepeatable results, and it’s confusing me.

I want to write tests to help me understand how/when my package is activated/deactivated. I could really use someone who knows looking at the specs and telling me whether I’ve written them correctly. Assume nothing, because I’m still groping around mostly in the dark.

Thanks to anyone who finds this.
@jbrains


Auto running packages
Can you force the activation of another package?
#2

I moved this to a new topic because I think there’s more help you can use than just package activation, but we’ll start there …

Activating a Package in Specs

The basic version is pretty simple. This is for packages that do not have activationCommands defined in their package.json:

describe 'Package Activation', ->
  beforeEach ->
    waitsForPromise ->
      atom.packages.activatePackage('package-name')

But since yours does, it is only slightly more complex:

describe 'Package Activation', ->
  [activationPromise, workspaceElement] = []
  
  executeCommand = (callback) ->
    atom.commands.dispatch(workspaceElement, 'package-name:some-command')
    waitsForPromise -> activationPromise
    runs(callback)

  beforeEach ->
    workspaceElement = atom.views.getView(atom.workspace)
    activationPromise = atom.packages.activatePackage('package-name')

  it 'executes a command', ->
    executeCommand ->
      expect(something).toEqual somethingElse

The way this works is that it tells Atom to activate the package but does not wait on it to finish activating. Then the test executes the command, whereupon Atom actually activates the package, so when you wait on the promise it is resolved and the test can continue.

(You can find sample code for this in my right-case package.)


Help writing specs, timeout error on activation
#3

Removing Commands on Package Deactivation

Your other question on your Gist was about commands being disposed of when the package is deactivated. When you call atom.commands.add it returns a Disposable that can remove the command when you’re done with it … if you save it. There is also a CompositeDisposable that can be used to dispose of multiple resources in one call. (The Disposable pattern is used all across Atom for things that are created and need to be removed later, so having this mechanism be consistent is really helpful.)

So, to remove the command when the package deactivates you would do this:

activate: ->
  @subscriptions = new CompositeDisposable
  @subscriptions.add atom.commands.add 'atom-workspace', 'package-name:some-command', =>
    @doSomethingCool()

deactivate: ->
  @subscriptions.dispose()

I often write specs in my packages to ensure that commands are created on activation and removed on deactivation. You can find an example in my tabs-to-spaces package.


#4

@leedohm I am newbie learning atom package develpoment. Can you explain why should we dispatch command to editorView before we wait for activationPromise? Shouldn’t we wait for package to be activated then dispatch the command?


#5

Packages can define activation commands that indicate that the package doesn’t have to be running before any of those commands are called. If your package uses them, you can activate your package by calling one of those commands.


#6

I understand what activation commands are but I am not sure if that answers my question. Can you clarify?


#7

A package with activationCommands isn’t truly activated (i.e. it’s activate method isn’t called) until one of the activationCommands is run. The activationPromise = atom.packages.activatePackage('package-name') line is just there to have a reference to the activationPromise object.


#8

I am confused about the sequence of events. From the code I expect these sequence of instuctions. Tell me if I am correct

  1. Dispatch command to atom of a package that may not have been activated.
  2. Wait until the package gets activated.
  3. The command gets executed by atom.

I feel that the order should be 2 --> 1 --> 3 . If the former order is correct, does the dispatched command waits in some sort of queue and wait till the package is activated?


#9

No, that’s not correct. Step 3 should be
3. Execute the callback that’s passed on to the runs function

The point is that we want to test a feature of our package, but for that we have to wait for the package to get activated, but the package doesn’t get activated unless one of its activation commands is executed. So we:

  1. execute one of the packages activation commands first with atom.commands.dispatch
  2. tell jasmine to wait for the package to be activated.
  • this can also be the first step, it doesn’t really matter because atom.packages.activatePackage returns a promise object that gets resolved when the command is dispatched.
  1. execute the callback function, in most cases the function that tests our feature

#10

Thanks I think I understand it now I guess.