how to unit-test setInterval in karma angularjs - unit-testing

app.directive('shuffleBlocks', function($timeout){
return {
link: function(sco,ele,att){
if (itemCnt <= 1) return;
/*Trigger function*/
function triggerEvent(){
...
}
ele.bind('click', triggerEvent);
setInterval(triggerEvent, 5000);
}
}
})
here I wrote the test
var elem = '<div shuffle-blocks><div>';
elem = mockCompile(elem)(rootScope.$new());
setInterval(function(){
expect(......).toBe(....)
});
Obviously this is not the right method,
does anyone know how to test $timeout and setInterval in karma?

UPDATE: The proper method of mocking setInterval in an angular 1.2+ application is to use angular's $interval service. Using the $interval service provides a number of benefits, but the one of most use in this situation is the $interval.flush() method. When writing tests, $interval exposes a .flush() method which allows you to mock the JS clock.
app.directive('shuffleBlocks', function($timeout, $interval){
return {
link: function(sco,ele,att){
if (itemCnt <= 1) return;
/*Trigger function*/
function triggerEvent(){ ... }
ele.bind('click', triggerEvent);
$interval(triggerEvent, 5000);
}
}
});
and then in your unit test:
var elem = '<div shuffle-blocks><div>';
elem = mockCompile(elem)(rootScope.$new());
$interval.flush(5000); // flush accepts the # of ms to be flushed
expect(......).toBe(....);
Hope that's helpful to anyone who looks up this answer in the future. I'll leave my previous answer for those still using 1.1X.
Previous Answer: According the jasmine docs, you should be able to just use the jasmine.Clock.useMock() function to mock the typical javascript clock and manually work your way through the interval. Since angular is just wrapping the native setTimeout function, I'm quite positive it should allow this to work, though I haven't tested it to be sure.
The jasmine docs for version 1.3 are here. Here's the code example that demonstrates how it works.
beforeEach(function() {
timerCallback = jasmine.createSpy('timerCallback');
jasmine.Clock.useMock();
});
it("causes a timeout to be called synchronously", function() {
setTimeout(function() {
timerCallback();
}, 100);
expect(timerCallback).not.toHaveBeenCalled();
jasmine.Clock.tick(101);
expect(timerCallback).toHaveBeenCalled();
});
The only issue I see is that your triggerEvent() function is local to your link function, so I don't know how you'll be able to get to it to mock it. But hopefully that points you in the right direction. If not, sorry, I tried.
UPDATE: The syntax for mocking the clock has changed in Jasmine 2.0. If you are using 2.0, please see the updated docs here.

Related

How to change $route in jest test case +VueJS +Jest

I am newbie to VueJS (and in test cases as well), apologize if this is already asked question,
I added a method in my component which checks the $route.name and returns a boolean accordingly,
BUT the issue appears in the test cases (JEST)
Have tried it with this but not working
isAbc () {
return this.$route.name === 'abc-route
}
This is my method for which I want to write test case,
const $route = {
name: 'abc-route'
}
const wrapper = shallowMount(Component, {
mocks: {
$route
}
})
I have also tried this approach
https://github.com/facebook/jest/issues/890#issuecomment-209698782
and checked if I can get this.$route.path but no luck with that as well.
Anyone can please mention what am I missing or doing wrong to get this?
In case if anyone gets stucked on it, I have solve it by changing the approach,
Instead of assigning $router, one should do the following
component.vm.$router.replace({ path: '/some/path', name: 'some-name' })
and then test it with
expect(component.vm.isAbc()).toBe(false)

How to unit test nested promises with jasmine js?

I am writing some Parse server cloud functions and trying to understand how I ll write a unit test that involve nested promises. e.g
Parse.Cloud.define("myfunction", function(request){
const common = require('./common')(Parse);
return common.firstPromise
.then(function(firstValue){
return common.secondPromise(firstValue, request.parama.p1);
})
.then(function(secondValue){
return common.thirdPromise(secondValue, request.param.p2);
})
.then(function(thirdValue){
return Parse.run("anotherFunction",{thirdValue:thirdValue});
})
.catch(function(e){
//log
return Promise.reject(e)
});
});
I am using a setup similar to like this. What are my options to make sure each nested promised called/not called with parameters etc. Is that testable ? or do I need to refactor and deal with each function in the promise chain ?

Is a Cache mock called more than once when browser-testing?

I'm trying to cover the following:
I'm using the following test code:
public function test_it_deletes_a_patient()
{
// ...
$cacheKey = vsprintf('%s.%s', [$this->doctorUser->id, 'backoffice.stats.patientsTotalCount']);
Cache::shouldReceive('has')->with($cacheKey)->once()->andReturn(false);
Cache::shouldReceive('increment')->with($cacheKey, -1)->once()->andReturn(true);
$response = $this->json('DELETE', route('patients.destroy', $this->patient), ['confirmation' => 'ELIMINAR']);
// ...
}
That triggers the following controller code:
public function destroy(Patient $patient, Request $request)
{
$this->authorize('delete', $patient);
$confirmation = $request->get('confirmation');
if ($confirmation != 'ELIMINAR') {
return response()->json(['success' => false]);
}
logger()->info("Deleting Patient Profile PATIENT_ID:[{$patient->id}]");
$patient->delete();
$this->updatePatientsCount(-1);
return response()->json(['success' => true]);
}
protected function updatePatientsCount($amount = 1)
{
$key = vsprintf('%s.%s', [auth()->user()->id, 'backoffice.stats.patientsTotalCount']);
if (Cache::has($key)) { // I want to mock for testing this
Cache::increment($key, $amount); // I want to mock for testing this
}
}
After test run I get:
alariva#trinsic:~/fimedi$ t --filter=test_it_deletes_a_patient
PHPUnit 7.3.1 by Sebastian Bergmann and contributors.
F 1 / 1 (100%)
Time: 6.53 seconds, Memory: 26.00MB
There was 1 failure:
1) Tests\Browser\Backoffice\PatientsTest::test_it_deletes_a_patient
Unable to find JSON fragment
["success":true]
within
[{"exception":"Mockery\\Exception\\NoMatchingExpectationException","file":"\/home\/alariva\/fimedi\/vendor\/mockery\/mockery\/library\/Mockery\/ExpectationDirector.php","line":92,"message":"No matching handler found for Mockery_0_Illuminate_Cache_CacheManager::has('2056e535e689ab723b3f44831b488f05f7fb8b90'). Either the method was unexpected or its arguments matched no expected argument list for this method\n\n","trace":[{"class":"App\\Http\\Middleware\\Language","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Pipeline\/Pipeline.php","function":"handle","line":151,"type":"->"},{"class":"Barryvdh\\Debugbar\\Middleware\\InjectDebugbar","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Pipeline\/Pipeline.php","function":"handle","line":151,"type":"->"},{"class":"Illuminate\\Auth\\Middleware\\Authenticate","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Pipeline\/Pipeline.php","function":"handle","line":151,"type":"->"},{"class":"Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Pipeline\/Pipeline.php","function":"handle","line":151,"type":"->"},{"class":"Illuminate\\Cookie\\Middleware\\EncryptCookies","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Pipeline\/Pipeline.php","function":"handle","line":151,"type":"->"},{"class":"Il
What I interpret after a couple of tests, is that it looks like once I mock Cache it is being called by some middlewares before reaching the tested block, so since those called methods are not mocked, the test fails because it does not know what to answer for those middleware calls.
Imagine I could successfully mock all the calls before getting to the tested codeblock, I would be able to make it reach. But that's not the way to go over it.
How can I mock Cache and avoid failure due to previous Cache calls that I'm not testing?
EDIT: I realized after getting to a solution that this is a misleading question. My actual need was:
How can I successfully cover those lines?
Sidenote: if I try to disable middlewares ($this->withoutMiddleware();) I get an AccessDeniedHttpException
alariva#trinsic:~/fimedi$ t --filter=test_it_deletes_a_patient
PHPUnit 7.3.1 by Sebastian Bergmann and contributors.
F 1 / 1 (100%)
Time: 12.95 seconds, Memory: 24.00MB
There was 1 failure:
1) Tests\Browser\Backoffice\PatientsTest::test_it_deletes_a_patient
Unable to find JSON fragment
["success":true]
within
[{"exception":"Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Foundation\/Exceptions\/Handler.php","line":201,"message":"This action is unauthorized.","trace":[{"class":"App\\Exceptions\\Handler","file":"\/home\/alariva\/fimedi\/vendor\/laravel\/framework\/src\/Illuminate\/Routing\/Pipeline.php","function":"render","line":83,"type":"->"},{"class":"Illuminate\\Foundation\\Exceptions\\Handler","file":"\/home\/alariva\/fimedi\/app\/Exceptions\/Handler.php","function":"render","line":65,"type":"->"},{"class":"Illuminate\\Foundation\\Exceptions\\Handler","file":
Maybe I can cherry-pick middlewares to disable?
I managed to cover the controller's method by encapsulating the custom Cache operation into a macro, so as to get the benefits of spliting into code units.
I moved my code into a macro (in the boot() of a service provider):
Cache::macro('incrementExisting', function($key, $amount) {
if (Cache::has($key)) {
Cache::increment($key, $amount);
}
return $this;
});
I refactored to use the macro
protected function updatePatientsCount($amount = 1)
{
$key = vsprintf('%s.%s', [auth()->user()->id, 'backoffice.stats.patientsTotalCount']);
Cache::incrementExisting($key, $amount);
}
I could get the desired coverage while I can still test the refactored code with unit testing.
Update I
Regarding the concern of handling many calls that are not mocked, I just learned from Adam Wathan that there exists shouldIgnoreMissing() and that would allow to use the Mocking approach for this case.
Update II
Write your tests first. When doing so it gets easier to avoid hard-to-test code.

How to make a unit test in meteor that adds a document to a collection? Mocking userId

Thank you for your help-
I'd like to know if my app successfully adds a document to the database using a unit test in Meteor. I'm using practicalmeteor:mocha and chai. The issue I'm running into is that I don't know how to mock a this.userId, it keeps telling me I'm not logged in.
it('inserts the draft agenda document into the collection', function() {
// TODO: mock document to insert into collection
// TODO: mock userId and Agenda.insert
this.userId = "Not an empty string";
console.log("before spec, changing this.userId: " + this.userId) //is "Not an empty string"
Meteor.call('createAgenda', mockAgenda, function(res) {
console.log("callback with response: " + res); //You're not logged-in. [not-logged-in]
console.log("this.userId: " + this.userId) //is undefined
}
}
see https://docs.meteor.com/api/methods.html#DDPCommon-MethodInvocation-userId for more info on user id
test runner fails to import files in client directory
MochaRunner.runServerTests: failures: 1 when meteor methods are called
I have to call the server side meteor methods that have been declared in the testing context as if I am on the client, but I can't import the client files or operate as if I'm a client
MochaRunner.runServerTests: Starting server side tests with run id R7ocZh3Qva3rExTL9 runs basically every time
This seems useful but hasn't worked for me yet https://forums.meteor.com/t/testing-methods-which-use-this-userid/2292/8
Thank you for your help, any code examples would be great.
Remarks
I wanted to post a comment but do not have enough reputation. So here are some remarks. Since you are testing on the server, you can call a Meteor method without a callback. This will result in a synchronous execution and simplify your test. Otherwise you will have to let the test know it is finished by calling the done function in your callback, see mocha docs.
Using mdg:validated-method
You can call a valited method and provide the context in which they execute using the _execute function. Below is an example taken from the todos sample project. For more examples you can take a look at their Lists and Todos tests.
it('makes a list private and updates the todos', function() {
// Check initial state is public
assert.isFalse(Lists.findOne(listId).isPrivate());
// Set up method arguments and context
const methodInvocation = {
userId
};
const args = {
listId
};
// Making the list private adds userId to the todo
makePrivate._execute(methodInvocation, args);
assertListAndTodoArePrivate();
// Making the list public removes it
makePublic._execute(methodInvocation, args);
assert.isUndefined(Todos.findOne(todoId).userId);
assert.isTrue(Todos.findOne(todoId).editableBy(userId));
});
Using standard methods
Another possiblity would be to bind the standard call function to the correct context. Note that this is just a thought and not tested.
var methodInvocation = {
userId: "some user id"
};
Meteor.call.bind(methodInvocation)('createAgenda', mockAgenda);

how can I write unit test to my meteor methods?

I found it a little complicated, and more complicated if I wrote my meteor methods in /lib folder, that I want is to test from server test folder my methods (unit test), but stub this.userId and also debugging or showing logs in server side does not help too much.
I was having too much problems with it, I'm using mochajs with velocity, does anyone would help me please? is someone know how can I write the units to meteor methods?
Mocha doesn't support unit tests, only Jasmine does currently. This is an example of how you would write a unit test in Jasmine for the server and use userId.
it("should return premium content to logged in users", function () {
// SETUP
var thisContext = {
userId : true
};
var expectedCursor = 'chapter_cursor1';
var _query = true, _modifiers = true;
Chapters.find = function(query, modifiers) {
_query = query;
_modifiers = modifiers;
return expectedCursor;
};
// EXECUTE
var actualCursor = Meteor.publishFunctions['chapters'].apply(thisContext);
// VERIFY
expect(actualCursor).toBe(expectedCursor);
expect(_query).toBe(undefined);
expect(_modifiers).toBe(undefined);
});
Taken from here: https://github.com/xolvio/Letterpress/blob/master/tests/jasmine/server/unit/chaptersSpec.js#L3