Jasmine testing AngularJS $http - testing

I'm trying to test a REST API wrapped in an AngularJS service using Jasmine async testing. I know, I should be, and am, running tests on the API on the server, and using a mock $httpBackend to test the service, but I'd still like to know how to do async tests where I need to.
The problem I'm having is my deferreds (returned by $http) never seem to resolve. Going past the service and trying to simply use $http has the same problem. What am I doing wrong here:
describe('Jasmine + Angular + $http', function() {
var injector;
beforeEach(function() {
injector = angular.injector(['ng']);
});
it('can be tested', function() {
injector.invoke(function($http) {
var complete = false;
runs(function() {
$http.get('...').then(function(res) {
complete = true;
});
});
waitsFor(function() {
return complete;
}, 'query to complete', 5000);
runs(function() {
expect(complete).toEqual(true);
});
});
});
});
(I'm using grunt-contrib-jasmine to run the tests)

The HTTP requests will not fire unless you call $httpBackend.flush().
More information can be found here: http://docs.angularjs.org/api/ngMock.$httpBackend

Related

Vue2 Composition Api - How do I fetch data from api?

I am using Vue2.6 with composition api.
I need to reroute to different pages depends on an api response.
Can someone please guide me, please?
I tried using onBeforeMount but it renders the UI elements then rerouted to the corresponding page to the api response..so I can see a flash of the wrong UI..
setup() {
const myData = 'myData';
onBeforeMount(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
I also tried adding async in the setup method but it errored saying my ref variables "Property or method "myData" is not defined on the instance but referenced during render."
async setup() {
const myData = 'myData';
onMounted(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
It looks like you're trying to handle routing (re-routing) dynamically from inside a component. I can't see the rest of the apps, so can't speak to the validity of such a solution, but would like you dissuade you from doing that. routing logic should, IMO, not be handled in a component. The components should mostly just handle the template and user interaction. By the time you're rendering a component, that API should have been resolved already.
I would recommend to resolve the API response before the route is
even completed. You or use a navigationGuard to resolve the API during the route execution. This functionality is asynchronous, so you can await the response before proceeding.
Alternatively, if you really want to handle it in the component, you will have that delay while the API is resolving, but you can implement some loader animation to improve the experience.

Understand how middleware works in Moleculer

I understand Mix-ins are to extend a common functionality across services. But Im not able to understand how middleware works in molecular and what problems It could help me solve.
Check the documentation how middleware works in Moleculer framework: https://moleculer.services/docs/0.13/middlewares.html
With middlewares you can extend the framework functionality with your custom logic.
Here is an example how a middleware looks like which extend service action handling:
const MyCustomMiddleware = {
// Wrap local action handlers (legacy middleware handler)
localAction(next, action) {
return function(ctx) {
// Change context properties or something
return next(ctx)
.then(res => {
// Do something with the response
return res;
})
.catch(err => {
// Handle error or throw further
throw err;
});
}
}
};

How do I mock redis when using supertest in Express?

I am building a REST API in Express and I'm trying to mock Redis in my Jasmine unit tests (using redis-mock).
If supertest is making a request to the API, how do I tell my app to use the mock Redis instead of the actual redis? .I know I'll probably need to create separate modules for redis that I can swap out somehow, just not sure how to swap it out for a regular request vs a supertest request.
Unit test:
describe('Instance API v1', () => {
it('returns a list of instances', (done) => {
request(app.default)
.get('/v1/instance')
.set('Authorization', 'Bearer '+authToken)
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')
.end((error) => (error) ? done.fail(error) : done());
});
});
Route handler:
getAll = (request: express.Request, response: express.Response) => {
let redis: RedisClient = request.app.locals.redisclient;
let keys:string[] = [];
let prefix = 'instance/*';
const scanner = new RedisScan(redis);
scanner.scan('instances/*', (err, matchingKeys) => {
if (err) throw(err);
// matchingKeys will be an array of strings if matches were found
// otherwise it will be an empty array.
console.log(matchingKeys);
response.json(matchingKeys);
});
};
in my previous experience, I didn't mock Redis in integration test so I can test the flow in full functionality.
If you want to mock the Redis, you must do it before you require and initiate your application in the test something like:
before(function() {
const matchingKeys = '1234';
sinon.stub(RedisScan.prototype, 'scan').yields(null, matchingKeys);
const app = require('./app');
return app.init(); // your init or whatever function to initiate your express app
});
Hope it helps

Can I set authorization headers with RequireJS?

We want to have 2 sets of resources for our AngularJS app (public/private) which uses RequireJS for dependency management. Basically everything on the login page would be public and once logged in, another angularjs app would be loaded (new requirejs config) that would load resources that require authentication to access.
Is there a way to configure requirejs to set an authorization header when loading resources?
It depends on what you mean by "resources" and how your server is configured. But in general - yes, since you are using AngularJS you can use the $httpProvider to inject an interceptor service.
For example, in a service:
var dependencies = ['$rootScope', 'userService'];
var service = function ($rootScope, userService) {
return {
request: function(config) {
var currentUser = userService.getCurrentUser();
var access_token = currentUser ? currentUser.access_token : null;
if(access_token) {
config.headers.authorization = access_token;
}
return config;
},
responseError: function (response) {
if(response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return response;
}
};
};
module.factory(name, dependencies.concat(service));
Then, after you configure your routes, you can use:
$httpProvider.interceptors.push( 'someService');
You can find some more information on interceptors here: https://docs.angularjs.org/api/ng/service/$http#interceptors
UPDATE
You might be able to use the text plugin to try and receive it, but I don't see the point in protecting client side code. Plus, if you want to use optimization the resources will just come in one file anyway...
config: {
text: {
onXhr: function (xhr, url) {
xhr.setRequestHeader('Authorization','Basic ' + token);
}
}
}
Refer to: custom-xhr-hooks
Another UPDATE
You could also use urlArgs (mainly used for cache invalidation) without using the text plugin:
require.config({
urlArgs: 'token='+token,
...
)}

How do I take a screenshot when a test in internjs fails?

I am having issues figuring out how to take a screenshot ONLY when a test fails in InternJs. I have this simple test in my registerSuite;
'verify google homepage': function () {
var url = 'https://www.google.com/';
return this.remote
.get(url)
.getCurrentUrl()
.then(function (data) {
assert.strictEqual(data, url, 'Incorrect URL');
})
.findByName('q')
.click()
}
I can simply create a screenshot using the following code;
.takeScreenshot
.then(function (data) {
fs.writeFileSync('/path/to/some/file', data, 'base64');
)}
I want to only take a screenshot, if the above test fails the assertion or is unable to find the locator.
I looked into the afterEach method, but I can't figure out how to get the status of the last test to apply a conditional.
So my question is, has anyone setup their internjs test to only take screenshots on failures and how was it accomplished?
It is not currently possible to interact with the currently executing test from beforeEach or afterEach methods; this capability is coming in the next version of Intern.
Selenium server, by default, provides a screenshot on every Selenium command failure, which is a Buffer object on the error.detail.screen property. If a Selenium command fails, just use this property which already has the screenshot waiting for you.
For assertion failures, you can create a simple promise helper to take a screenshot for you:
function screenshotOnError(callback) {
return function () {
try {
return callback.apply(this, arguments);
}
catch (error) {
return this.remote.takeScreenshot().then(function (buffer) {
fs.writeFileSync('/path/to/some/file', buffer);
throw error;
});
}
};
}
// ...
'verify google homepage': function () {
return this.remote.get(url).getCurrentUrl().then(screenshotOnError(function (actualUrl) {
assert.strictEqual(actualUrl, url);
}));
}
If it’s too inconvenient to wrap all your callbacks manually like this, you can also create and use a custom interface for registering your tests that wraps the test functions automatically for you in a similar manner. I’ll leave that as an exercise for the reader.
You can use catch method at the end of your chain and use error.detail.screen as suggested by C Snover.
'verify google homepage': function () {
return this.remote
.get(require.toUrl('./fixture.html'))
.findById('operation')
.click()
.type('hello, world')
.end()
.findById('submit')
.click()
.end()
.catch(function(error){
fs.writeFileSync('/tmp/screenshot.png', error.detail.screen);
})
}
I've been playing with this today and have managed to get it for an entire suite rather than needing to add the code to every single test which seems quite needless.
var counter = -1,
suite = {
beforeEach: function () {
counter++;
},
afterEach: function () {
var currentTest = this.tests[counter];
if (!currentTest.error) {
return;
}
this.remote
.takeScreenshot().then(function (buffer) {
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
fs.writeFileSync('/tmp/' + currentTest.name + '.png', buffer);
});
}
};
The annoying thing you will need to do is do this for every test suite rather than "globally" but is much better than doing it for every test.
Building on the answer by Hugo Oshiro,
// tests/support/CleanScreenshots.js
define([
'intern/dojo/node!path',
'intern/dojo/node!del',
], function(path, del) {
return new Promise((resolve, reject) => {
let directory = 'tests/screenshots';
del(path.join(directory, '**/*'))
.then(resolve)
.catch(reject);
});
});
Then in your intern config:
/* global define */
define([
'tests/support/CleanScreenshots'
], function (CleanScreenshots) {
return {
...
setup: function () {
return CleanScreenshots();
},
...
};
});
According to this issue, starting with the Intern 3.0 you can do a custom reporter that take an Screenshots when test fail. So you can centralize it in a simple way, just referencing the custom reporter in your config.js. In my case, what can I just add a reporter array in the config.js with the path to my custom array:
reporters: [
{ id: 'tests/support/ScreenShot' }
],
than I made an custom reporter overriding testFail:
'use strict';
define([
'intern/dojo/node!fs',
], function(fs) {
function ScreenShot(config) {
config = config || {};
}
ScreenShot.prototype.testFail = function(test) {
test.remote.takeScreenshot().then(function(buffer) {
try {
fs.writeFileSync('./screenshots/' + test.parent.name.replace(/ /g, '') + '-' +
test.name.replace(/ /g, '') + '.png', buffer);
} catch (err) {
console.log('Failed to take a screenshot: ' + err);
}
});
};
return ScreenShot;
});
Pay attention to the relative paths both to reference the custom reporter and the place for screenshots. They all seems to be taken considering where you run intern-runner, not the place the source files are located.
For more info about custom reporters go to this page.