Unit testing asynchronous call in angular - angular-test

I have following function in a service 'MyService':
myFunction(input: MyInput){
this.someService.someFunction(<any> input).then(result => {
console.log('Somefunction worked successfully');
return result;
}).catch(reason => {
throw new Error('Somefunction failed');
})
}
And unit test for myFunction is as:
// create test data
spyOn(someService, 'someFunction').and.returnValue(Promise.resolve(dummyResult));
// invoke target unit
const response = myService.myFunction(dummyInput);
// validations
expect(someService.someFunction).toHaveBeenCalled();
expect(someService.someFunction).toHaveBeenCalledTimes(1);
expect(someService.someFunction).toHaveBeenCalledWith(dummyInput);
expect(response).toBe(dummyResult)
First three validations pass, but last one doesn't as call to someFunction is asynchronous and hence response is still undefined at time of validation.
How to handle such scenario?
I came across fakeAsync but examples are a bit different from this.

Related

mockRestore does not clear a jest.spyOn().mockImplementation mock

I am mocking Date.now() implementation returning a specific date however, after the test is done the afterAll + mockRestore() doesn't quite rid of the mock.
When I run another test the date now is still mocked to 1626764400000. Is there a different function I have to use to reset the mock? I have already used: mockReset, mockClear, jest.clearAllMocks.
beforeAll((): void => {
jest.spyOn(Date, 'now').mockImplementation(() => 1626764400000);
});
afterAll((): void => {
jest.clearAllMocks();
jest.spyOn(Date, 'now').mockRestore();
});
I have solved a similar issue by calling mockRestore of the returned value of the jest.spyOn(), that also returns a Jest mock function.
Oficcial docs.

Why jest expects an anonymous function to catch an error?

I have not comprehended what's the reason behind the fact that expects a curried function when I want to test the output of the error message. If it was going to be a return value a direct call to the function leads to the value to be tested correctly in .toBe
function calculateMedian({numbers}) {
if (Array.isArray(numbers) && numbers.length === 0) {
throw new Error('Cannot calcuate median without any numbers');
}
}
However, if i were to test the following snipped without the anonymous function the test will simply fail. What is the reason behind it?
Passing Test
it('should throw an error when given an empty array', () => {
expect(() =>
calculateMedian({
numbers: [],
}),
).toThrow('Cannot calcuate median without any numbers');
});
Failing Test
it('should throw an error when given an empty array', () => {
expect(calculateMedian({numbers: []})
).toThrow('Cannot calcuate median without any numbers');
});
expect and toThrow are just function calls. So, for the assertion on exception to work, the thing you pass as expect argument needs to allow for execution controlled by the testing framework.
The flow is similar to:
expect() saves the lambda as variable
toThrow() executes the saved variable in a try/catch block and tests the caught exception.
The way you would do it without the toThrow method would be similar to:
try {
calculateMedian({numbers: []};
fail();
} catch (err) {
expect(err.message).toBe('Cannot calcuate median without any numbers')
}
If, instead of passing a lambda/function you simply invoke the function, the error will be thrown before program control gets to the toThrow method. The test will fail because of the thrown error.

In TestCafe is there a way to know if the test passed or failed in after hook?

I am trying to mark tests as pass/failed through a rest API (Zephyr) while my testcafe tests are running. I was wondering if it's possible in the after or afterEach hook to know if the test passed/failed so that I can run some script based on the result.
Something like:
test(...)
.after(async t => {
if(testFailed === true) { callApi('my test failed'); }
})
I see two ways in which to solve your task. First, do not subscribe to the after hook, but create your own reporter or modify the existing reporter. Please refer to the following article: https://devexpress.github.io/testcafe/documentation/extending-testcafe/reporter-plugin/#implementing-the-reporter
 
The most interesting method there is reportTestDone because it accepts errs as a parameter, so you can add your custom logic there.
The second approach is using sharing variables between hooks and test code
You can write your test in the following manner:
test(`test`, async t => {
await t.click('#non-existing-element');
t.ctx.passed = true;
}).after(async t => {
if (t.ctx.passed)
throw new Error('not passed');
});
Here I am using the shared passed variable between the test code and hook. If the test fails, the variable will not be set to true, and I'll get an error in the after hook.
This can be determined from the test controller, which has more information nested within it that is only visible at run time. An array containing all the errors thrown in the test is available as follows
t.testRun.errs
If the array is populated, then the test has failed.

Testing ember components with promises

I've hit a wall in testing an ember component.
I have component that has an action
pseudocode
actions: {
doSomething(){
this.set('showSpinner', true);
this.model.serverOperation().then(()=>{
this.set('showSpinner', false);
this.service.doSomething();
})
}
}
in my test, i would like to assert that showSpinner is true when the action is invoked, then becomes false after the promise resolves. So my test looks like (pseudocode, using ember-sinon-qunit):
const deferred = Ember.RSVP.defer();
const modelMock = this.mock(this.model);
const serviceMock = this.mock(this.service);
modelMock.expects('serverOperation').returns(deferred.promise);
serviceMock.expects('doSomething);
this.$('selector').click(); // invokes 'doSomething'
assert(this.showSpinner, true)
deferred.resolve();
assert(this.showSpinner, true)
the problem is, on the deferred.resolve() call, the last assert fires before the then method in the component.
Is there a canonical way to handle this sort of thing in ember?
I tried using async to test, but in that case a few interesting things happen:
I change the final assert to execute in a setTimeout, and then the assert on showSpinner passes, but
the test still exits before then runs (so before the timeout callback fires), and since we are using ember-sinon-qunit, the test harness fails on the serviceMock expectation.
Put the last assert in a then() after call to deferred.resolve()
deferred.resolve();
deferred.promise.then(()=> {
assert(this.showSpinner, true);
});

Reusable functions for Protractor test framework

I use Protractor Test Framework and need to use some the same operations for different cases. Like Authentication procedure.
The question is: What's the correct way to use own functions in Protractor?
I remember this tool works: 1) asynchronous and 2) its functions return promises.
Must the reusable function return the promise for make possibility do .then() operation or this function may return no value?
An Example (correct or no):
describe('Login procedure', function() {
it('Login Username', function () {
browser.get('anurl.com');
auth('username', 'password').then(function(){console.log('NICE TO MEET YOU')});
});
var auth = function(loginstr, passwordstr) {
return element(by.css('div[class="login"]')).isDisplayed().then(function (result) {
if (result) {
element(by.css('input[name="email"]')).clear().sendKeys(loginstr).then(
function () {
element(by.css('input[name="password"]')).clear().sendKeys(passwordstr).then(function () {
element(by.css('button[class="submit"]')).click().then(function () {
return element(by.id('welcome')).isPresent();
});
});
});
}
});
}
Thanks!
Your example looks fine.
It is good practice to return a promise from your utility functions (so callers can then off of it if they want). But it is not required.
In practice, the methods you are invoking that create promises (e.g., click or isDisplayed, etc) implicitly register the created promise with the control flow, so the implicit synchronization will not be impacted by refactoring the calls into your own functions.
See the Protractor Page Objects for a similar approach.
Our team uses Orchid-js with Jasmine and Protractor.
It's an extension that makes defining your own functions automatic.
In this case your code will still work, you would just be able to automatically reuse your 'Login procedure' and 'Login Username' functions as well.
Describe('Login procedure', function(username,password) {
It('Login Username', function (username,password) {
browser.get('anurl.com');
auth(username, password).then(function(){console.log('NICE TO MEET YOU')});
})(username,password);
})('username','password');
Then reuse it later
Describe('Login procedure')('differentUsername','differentPassword');