Package not activating when running specs - javascript

I've created a package for Atom called quick-fold that jumps to the next foldable line and folds it on the command quick-fold:fold-next. I wanted to start getting into Atom specs so I can run tests on this package, however I've hit this problem where the package is just never activated when running the specs.
quick-fold-spec.js:
describe('QuickFold package', () => {
let editor, editorView;
beforeEach(async () => {
await atom.packages.activatePackage('language-javascript');
await atom.workspace.open('sample.js');
editor = atom.workspace.getActiveTextEditor();
editorView = atom.views.getView(editor);
});
describe('when the specs are run', () => {
it('opens the sample file', () => expect(!editor.isEmpty()).toBe(true));
// true
});
describe('when the quick-fold:fold-next event is triggered', () => {
beforeEach(async () => {
// Try to activate package by dispatching command:
atom.commands.dispatch(editorView, 'quick-fold:fold-next');
await atom.packages.activatePackage('quick-fold'); // Never resolves
});
it('activates the package', () => {
expect(atom.packages.isPackageActive('quick-fold')).toBe(true);
});
it('moves the cursor to a different line number', () => {
expect(editor.getCursorScreenPosition().row).not.toBe(0);
});
});
});
But atom.packages.activatePackage('quick-fold') never resolves. The package doesn't activate and instead it times out:
timeout: timed out after 5000 msec waiting for spec promise to resolve
The activation command is set in package.json:
"activationCommands": {
"atom-workspace": "quick-fold:fold-next"
},
so dispatching this should activate the package, and then the await atom.packages.activatePackage('quick-fold') should resolve. But the cursor position doesn't change and the package doesn't get activated.
(Note that atom.packages.activatePackage('quick-fold') is merely a promise - it doesn't activate the package but it resolves when the package gets activated.)

As is often the case, I figured it out in the end...
1. The beforeEach() function is missing a runs()
It should be
beforeEach(async () => {
await atom.packages.activatePackage('language-javascript');
await atom.workspace.open('sample.js');
runs(() => {
editor = atom.workspace.getActiveTextEditor();
editorView = atom.views.getView(editor);
return activationPromise = atom.packages.activatePackage('quick-fold');
});
});
where the runs() function returns a promise on activation of the package.
From the docs:
Specs are written by defining a set of blocks with calls to runs, which usually finish with an asynchronous call.
I'm too tired right now to understand exactly what that means but it rings true here.
2. The activation commands in package.json should be based on atom-text-editor
I.e., not atom-workspace
"activationCommands": {
"atom-text-editor": "quick-fold:fold-next"
},
This is probably because we have atom.commands.dispatch(editorView, 'quick-fold:fold-next') where the commands are dispatched to editorView = atom.views.getView(editor) instead of the Atom workspace.
Refactored - the "standard" way of doing it
describe('QuickFold package', () => {
let editor, editorView, activationPromise;
const foldNext = async (callback) => {
atom.commands.dispatch(editorView, 'quick-fold:fold-next');
await activationPromise;
return callback();
};
beforeEach(async () => {
await atom.packages.activatePackage('language-javascript');
await atom.workspace.open('sample.js');
runs(() => {
editor = atom.workspace.getActiveTextEditor();
editorView = atom.views.getView(editor);
return activationPromise = atom.packages.activatePackage('quick-fold');
});
});
describe('when the specs are run', () => {
it('opens the sample file', () => expect(!editor.isEmpty()).toBe(true));
});
describe('when the quick-fold:fold-next event is triggered', () => {
it('activates the package', () => {
return foldNext(() => expect(atom.packages.isPackageActive('quick-fold')).toBe(true));
});
it('moves the cursor to a different line number', () => {
return foldNext(() => expect(editor.getCursorScreenPosition().row).not.toBe(0));
});
});
});

Related

Why isn't my jest mock function implementation being called?

I have the following jest test configuration for my collection of AWS JS Node Lambdas. I have a module called dynamoStore I reference in several different lambdas package.json and use within the lambdas. I am trying to get test one of these lambdas by mocking the dynamo store module as it makes calls to dynamoDb. The problem is that the jest.fn implementation never gets called. I confirmed this by sticking a breakpoint in that line as well as logging the value the calling methods returns from it.
When I check lambda1/index.js in the debugger getVehicleMetaKeysFromDeviceId() is a jest object but when it is called it doesn't use my mock implementation
How do I get this implementation to work? Have I set up my mock incorrectly?
dynamoStore/vehicleMetaConstraints
exports.getVehicleMetaKeysFromDeviceId= async (data) => {
return data
};
dynamoStore/index.js
exports.vehicleMetaConstraints = require("./vehicleMetaConstraints");
...
lambda1/index.js
const { vehicleMetaStore } = require("dynamo-store");
exports.handler = async (event, context, callback) => {
const message = event;
let vehicle_ids = await vehicleMetaStore.getVehicleMetaKeysFromDeviceId(message.id);
// vehicle_ids end up undefined when running the test
}
lambda1/index.test.js
const { vehicleMetaStore } = require("dynamo-store");
jest.mock("dynamo-store", () => {
return {
vehicleMetaStore: {
getVehicleMetaKeysFromDeviceId: jest.fn(),
},
};
});
describe("VehicleStorageLambda", () => {
beforeEach(() => {
jest.resetModules();
process.env = { ...env };
});
afterEach(() => {
jest.clearAllMocks();
});
test("Handles first time publish with existing device", async () => {
let functionHandler = require("./index");
vehicleMetaStore.getVehicleMetaKeysFromDeviceId.mockImplementationOnce(() =>
// This never gets called
Promise.resolve({
device_id: "333936303238510e00210022",
})
);
await functionHandler.handler({});
});
});
Remove the call to jest.resetModules() in beforeEach. That's re-importing your modules before each test, and wiping out your mocks.
https://stackoverflow.com/a/59792748/3084820

Node: how to test multiple events generated by an async process

I need to test an async Node.js library which periodically generates events (through EventEmitter) until done. Specifically I need to test data object passed to these events.
The following is an example using mocha + chai:
require('mocha');
const { expect } = require('chai');
const { AsyncLib } = require('async-lib');
describe('Test suite', () => {
const onDataHandler = (data) => {
expect(data.foo).to.exist;
expect(data.bar).to.exist;
expect(data.bar.length).to.be.greaterThan(0);
};
it('test 1', async () => {
const asyncLib = new AsyncLib();
asyncLib.on('event', onDataHandler); // This handler should be called/tested multiple times
await asyncLib.start(); // Will generate several 'events' until done
await asyncLib.close();
});
});
The problem is that even in case of an AssertionError, mocha marks the test as passed and the program terminates with exit code 0 (instead of 1 as I expected).
The following uses done callback instead of async syntax, but the result is the same:
require('mocha');
const { expect } = require('chai');
const { AsyncLib } = require('async-lib');
describe('Test suite', () => {
const onDataHandler = (data) => {
expect(data.foo).to.exist;
expect(data.bar).to.exist;
expect(data.bar.length).to.be.greaterThan(0);
};
it('test 1', (done) => {
const asyncLib = new AsyncLib();
asyncLib.on('event', onDataHandler);
asyncLib.start()
.then(asyncLib.close)
.then(() => done());
});
});
I have also tried with a "pure" Node.js approach using the native assert.ok without any 3rd part library:
const { strict: assert } = require('assert');
const { AsyncLib } = require('async-lib');
const test = async () => {
const onDataHandler = (data) => {
assert.ok(data.foo != null);
assert.ok(data.bar != null);
assert.ok(data.bar.length > 0);
};
asyncLib.on('event', onDataHandler);
const asyncLib = new AsyncLib();
await asyncLib.start();
await asyncLib.close();
}
(async () => {
await test();
})();
Even in this case, an AssertionError would make the program to terminate with exit code 0 instead of 1.
How can I properly test this code and make the tests correctly fail in case of an assertion error?
There are some things that you need to fix to make it works:
Make your test async, because the test is going to execute the expects after a certain event is received meaning it's going to be asyncronous.
Your event handler in this case onDataHandler should receive the done callback because there is the way how you can indicate to mocha that the test was finished successful as long as the expects don't fail.
I wrote some code and tested it out and it works, you have to make some changes to adapt your async library though:
describe('Test suite', function () {
const onDataHandler = (data, done) => {
expect(data.foo).to.exist;
expect(data.bar).to.exist;
expect(data.bar.length).to.be.greaterThan(0);
done();
};
it('test 1', async function (done) {
eventEmitter.on('event', (data) => onDataHandler(data, done));
setTimeout(() =>{
eventEmitter.emit('event', {
})
}, 400)
});
});

How to wait my custom command finish, then executing remaining Cypress commands

I'm getting trouble with Cypress asynchronous mechanism. I have a custom command that is placed in this file
class HeaderPage {
shopLink = 'a[href="/angularpractice/shop"]'
homeLink = ''
navigateToShopPage() {
cy.get(this.shopLink).click()
}
sshToServer() {
setTimeout(() => {
console.log('Connecting')
}, 5000)
console.log('Connected')
}
}
export default HeaderPage
The function sshToServer is simulated to pause 5000ms. So I want Cypress remaining test will be hold and wait for this function completed. How can I do that? Thanks in advance.
import HeaderPage from "../support/pageObjects/HeaderPage"
describe('Vefiry Alert and Confirm box', () => {
const headerPage = new HeaderPage()
it('Access home page', () => {
cy.visit(Cypress.env('url') + 'AutomationPractice/')
});
it('SSH to server', () => {
headerPage.sshToServer()
});
it('Verify content of Alert', () => {
cy.get('#alertbtn').click()
cy.on('window:alert', (alert) => {
expect(alert).to.equal('Hello , share this practice page and share your knowledge')
})
});
You can issue a new cy.wrap command with a value null and calling your async function in the .then function. Cypress will resolve that async function automatically and then move on to the next test.
First, you should convert your sshToServer method to an async(promise) function:
sshToServer() {
console.log('Connecting');
return new Promise((resolve) => {
setTimeout(() => {
console.log('Connected');
resolve();
}, 5000);
});
}
Then, in your spec:
it('SSH to server', { defaultCommandTimeout: 5000 }, () => {
cy.wrap(null).then(() => headerPage.sshToServer());
});
Note that I have also used a bigger for the spec defaultCommandTimeout since the default timeout is 4 seconds which is shorter than your sshToServer method and would cause the test to fail if not using a bigger timeout.
Sorry for late answer but i think this is the easiest way to do it
cy.wait(milliseconds)

Jest - Understanding execution order of a describe() and it()

I would like to understand why all the blocks describe() run before the it() in inside of each describe().
Here's a CodeSandbox example with a log per each describe and it block.
describe("sum A", () => {
window.innerWidth = 100;
console.log("describe A", window.innerWidth);
beforeAll(() => {
window.innerWidth = 105;
console.log("describe A before", window.innerWidth);
});
it("1. should add 1 and 2", () => {
console.log("it A1", window.innerWidth);
expect(1 + 2).toBe(3);
});
});
describe("sum B", () => {
console.log("describe B", window.innerWidth, "why does it run before it A1?");
beforeAll(() => {
window.innerWidth = 205;
console.log("describe B before", window.innerWidth);
});
it("1. should add 1 and 2", () => {
console.log("it B1", window.innerWidth);
expect(1 + 2).toBe(3);
});
});
You'll notice that the log from the second describe block runs before the it() inside the first describe block.
Why does that happen? Should we avoid doing stuff in that part of the code and prefer using beforeAll() when we need to share and scope data in that describe block?
When Jest runs it looks for all of the test files and runs each one.
Each test file runs within an environment provided by Jest that includes globals like describe, it, beforeAll, etc. All of these globals have a callback parameter that defines their behavior.
When a test file runs the top-level code runs...including any top-level describe calls.
When a describe runs it registers a test suite, and then its callback is called immediately.
This is different than it, beforeAll, beforeEach, etc. where the callback is recorded but not immediately called.
This means that all describe callback functions are called depth-first in the order they appear in a test file, as can be seen in this simple example:
describe('1', () => {
console.log('1');
describe('2', () => { console.log('2'); });
describe('3', () => {
console.log('3');
describe('4', () => { console.log('4'); })
describe('5', () => { console.log('5'); })
})
describe('6', () => { console.log('6'); })
})
describe('7', () => {
console.log('7');
it('(since there has to be at least one test)', () => { });
})
...which logs 1 - 7 in order.
This initial run of all the describe callbacks is called the collection phase during which the test suites are defined and all of the callbacks for any beforeAll, beforeEach, it, test, etc. are collected.
After the collection phase completes, Jest...
runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.
For each test (each callback function registered with the global it or test functions) Jest links together any before callbacks, the test callback itself, and any after callbacks and runs the resulting functions in order.
Should we avoid doing stuff in that part of the code and prefer using beforeAll() when we need to share and scope data in that describe block?
For simple stuff that isn't shared it's fine to have it in the describe:
describe('val', () => {
const val = '1';
it('should be 1', () => {
expect(val).toBe('1'); // Success!
});
});
...but code in the describe can cause issues with shared data:
describe('val', () => {
let val;
describe('1', () => {
val = '1';
it('should be 1', () => {
expect(val).toBe('1'); // FAIL! (val gets set to 2 in the second describe)
})
})
describe('2', () => {
val = '2';
it('should be 2', () => {
expect(val).toBe('2'); // Success!
})
})
});
...which can be fixed either by using before calls:
describe('val', () => {
let val;
describe('1', () => {
beforeEach(() => {
val = '1';
});
it('should be 1', () => {
expect(val).toBe('1'); // Success!
})
})
describe('2', () => {
beforeEach(() => {
val = '2';
});
it('should be 2', () => {
expect(val).toBe('2'); // Success!
})
})
});
...or simply scoping the data to the describe:
describe('val', () => {
describe('1', () => {
const val = '1';
it('should be 1', () => {
expect(val).toBe('1'); // Success!
})
})
describe('2', () => {
const val = '2';
it('should be 2', () => {
expect(val).toBe('2'); // Success!
})
})
});
In your example you are using window.innerWidth which is a shared global, so you will want to use before functions since it can't be scoped to the describe.
Also note that you can't return anything from a describe so if your tests require any asynchronous setup then you will need to use a before function where you can return a Promise for Jest to await:
const somethingAsync = () => Promise.resolve('1');
describe('val', () => {
let val;
beforeAll(async () => {
val = await somethingAsync();
});
it('should be 1', () => {
expect(val).toBe('1'); // Success!
});
});

How to force Jest unit test assertion to execute before test ends?

I have the following test in my react native application, but the test should fail (because the action returned is not equal to the action I put in expectedActions. My guess is that it is passing because the expect test runs after the test has completed.
How can I force the test to wait until the promise is completed and the expect test runs? Is there another way of doing this?
describe('authorize actions', () => {
beforeEach(() => {
store = mockStore({});
});
it('should create an action to signify successful auth', () => {
auth.authorize.mockImplementation(() => Promise.resolve({"something": "value"}));
const expectedActions = [{"type":"AUTHORIZE_RESPONSE","payload":{"something":"sdklfjsdf"}}];
authorizeUser(store.dispatch, store.state).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
})
});
Ok, looks like I just missed some of the Jest docs - if you return the promise, i.e. return auth.authorize.mockImplementation(() => Promise.resolve... then Jest will wait until it's completed before continuing.
The are varios ways to test async code. Check the docs for examples: https://facebook.github.io/jest/docs/en/asynchronous.html
One could be returning the promise:
describe('authorize actions', () => {
beforeEach(() => {
store = mockStore({});
});
it('should create an action to signify successful auth', () => {
auth.authorize.mockImplementation(() => Promise.resolve({"something": "value"}));
const expectedActions = [{"type":"AUTHORIZE_RESPONSE","payload":{"something":"sdklfjsdf"}}];
return authorizeUser(store.dispatch, store.state).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
})
});

Categories

Resources