my goal is to create an automatic E2E test that fills a form and clicks on the "send" button. After that I need to wait the mock api response before set the test as Passed or not.
First question: Is this possible in the same E2E test?
I'm using AngularJs 1.5.5, ngMocks and Protractor\Jasmine.
Right now I'm able to fill the form using
element(by.model('xxxx')).sendKeys('xxxx');
and click on the "Send" button using
element(by.css('input[type="button"]')).click();
I created also an api mock for this test in a new js file that I included in page. The code is the following:
var testAppDEV = angular.module('testAppDEV', ['testApp', 'ngMockE2E']);
testAppDEV.run(function ($httpBackend) {
// Api to save the form
$httpBackend.whenPOST('/api/save').respond(function (method, url, data) {
var formData = angular.fromJson(data);
if (Object.keys(formData).length == 3) {
// url, data, headers
return [200, { errorCode: null }, {}];
}
else
{
return [400, { errorCode: '1' }, {}];
}
});
});
Now I need to add the code to my Jasmine test that wait for the mock api response and according to response, set the test as Passed or Failed.
Can you help me?
This is a first step because the next will be to integrate this test with Jenkins, like I did with Unit tests..
Every hint is welcome :)
Related
I'm using Cypress to create some specs against my React app. My react app uses fetch to fetch data from an external api (isomorphic-fetch)
The fetch requests in my app are like so
import fetch from 'fetch'
...
fetch('http://www.external-server.com/ideas.json')
.then((response) => {
if (response.status >= 400) {
}
return response.json().then((result) => {
this._data = result
this._data((ele) => ele.key = ele.id)
});
})
In my Cypress specs, I want my regular specs to hit my lcoahost:3000 to get the initial page (which houses my React app). My react app in turn would normally make an external request (http://www.external-server.com/ideas.json) but in my specs I want to stub out that request and have that endpoint return fake data in my specs only.
The Cypress docs for cy.route() here, describe that I should be able to do something like
cy.server()
cy.route('http://www.external-server.com/ideas.json', [
{
id: 1,
name: 'john'
}
])
I attempted to put this into a beforeEach that runs in the context of my spec (thus running before every spec).
You will note that when I run the specs in the Cypress test running, it appears in the console output that the endpoint SHOULD be stubbed.
However, by examination, I can see that my app is in fact making the request to the real server, and calling the real endpoint (not stubbing it).
I tested several times and I am certain this is the behavior.
I found a solution online I will post below to answer my question
the solution is add to cypress/support/commands.js
this small hack will turn the window fetch into a no-op (disabling it) and will allow the native stubbing in Cypress to work without any alterations.
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
const opts = Object.assign({}, options = {}, {
onBeforeLoad: (window, ...args) => {
window.fetch = null;
if (options.onBeforeLoad) {
return options.onBeforeLoad(window, ...args);
}
},
});
return originalFn(url, opts);
});
I found a lot of similar discussion about this topic but unfortunately none of them fit my scenario.
I'm trying to mock the backend response from Protractor for testing a new functionality that is not present in the real API at the moment.
I tried different ways for achieving that but with no luck. Every time I run the protractor test, the http request is performed to real API instead of intercepting the request.
Here is my scenario:
I have an AngularJS application and there is a search input box in one view like this:
<input type="text" class="form-control rounded input-lg" placeholder="Search Contacts" ng-model="contactCtrl.filter" ng-change="contactCtrl.inspectFilter()" focus="true" id="inputSearch">
Then, I have a controller for that:
function inspectFilter() {
$q.all([
comService.indexContacts($rootScope.$user.cloudContacts, vm.filter)
.then(function(response) {
vm.contacts = angular.copy(contacts);
})
.catch(function() {
})
]).then(function() {
});
}
}
And the comService.indexContacts that performs the http request:
function indexContacts(url, filter) {
var filtered_url = filter ? url + '?displayName=' + encodeURIComponent(filter) : url;
initializeRequest();
req = {
headers : {
'Authorization' : getAuthenticationToken()
},
method : 'GET',
url : filtered_url
};
return $http(req);
}
I'm not going to explain the logic of everything but let's just say that when the user type something in the input filed, the indexContacts function triggers a GET request to the API and the user can see a list of contacts rendered on the screen.
Now I would very like to intercept that $http(req) in my Protractor test and return a mock JSON back but I don't understand how.
'use strict';
describe('Making a call from the contact detail screen', function() {
beforeAll(function() {
contacts.goToContacts();
element(by.id('inputSearch')).clear().sendKeys('gai');
});
describe('UAT1 - Clicking the number to make a call', function() {
it('Given that the user is on the Cloud contact/user detail screen', function() {
element(by.repeater('contact in contactCtrl.results').row(0)).element(by.css('.tdName')).click();
dom.waitForElementDisplayed(element(by.css('.contact-modal')));
});
...
...
Ok, what I do in here is injecting some text into the search field with: element(by.id('inputSearch')).clear().sendKeys('gai'); and this works, but, I want to intercept the http request triggered by the previous comService and, instead, return a mock JSON back to the application to render a custom list of users instead of using the real API for that.
How can I do that????
I am testing AngularJS application which is dependent on API and I am new to do API testing. I login to page which is AngularJS app. When I login it calls api I am able to test UI stuffs but now I need to test API.
For example UI code, I am using page object:
LoginPage.setUserName('test#test.com');
LoginPage.setPassWord('test');
LoginPage.clickButton();
This code works fine, on click of submit button it calls API to process the login. Now I need to test that API call:
On click it calls:
GET https://192.168.00.00:0000/config/settings.json
with response:
{
"domain": "https://192.168.000.00",
"port":1111
}
and then it calls:
POST https://192.168.000.00:1111/api/Login
with response:
{
"status":"SUCCESS",
"message":"Login Successful",
"results: {
"id":96,
"userName":"test#test.com",
"password":null,
"firstName":"Test",
"lastName":"Testing",
"employeeCode":"007",
"location":2
}
}
Now I need to test this scenario with mocking it. I wrote this mocking code:
exports.signup_request = function() {
angular.module('myApp', ['ngMockE2E']).run(function($httpBackend) {
$httpBackend.whenGET('/api/Login/').respond({
"status":"SUCCESS",
"message":"Login Successful",
"results": {
"id":96,
"userName":"test#test.com",
"password":null,
"firstName":"test",
"lastName":"Testing",
"employeeCode":"007",
"location":2
}
});
// allow views directory to go to real $http
$httpBackend.whenGET(/^\/views\//).passThrough();
// we have a real /api/customer service, let it through
$httpBackend.whenGET(/^/api/Login//).passThrough();
});
}
My spec file which loads mock js file where I have written $httpBackend related code:
beforeEach(function(){
mockModule = require('./mock');
browser.ignoreSynchronization = true;
});
it("ensure user can signup for the application", function(){
browser.addMockModule('httpBackendMock', mockModule.signup_request);
// DONT NO WHAT TO WRITE HERE;
});
When I run this spec it shows browser.addMockModule('httpBackendMock', mockModule.signup_request); is undefined.
I'm writing an end-to-end test that simulates user authentication with Protractor. A user feels in her credentials and clicks a Submit button. As a result, the server returns an access token in a JSON response that can be used for other REST API calls. I'd like to save this token to a file.
There's a similar question on capturing a response of a GET request here, but I'm not sure it's a good idea to send another request after I click the button.
How can I capture the response after a button click?
Here is my idea about how to catch HTTP responses. Protractor provides a method browser.addMockModule() (docs) - it is used to add custom Angular modules to a page, which are usually used to mock outcoming requests and provide custom response. But we do not need to mock requests, it would be enough to just listen for whatever comes from a server. It can be achieved with the help of Angular HTTP interceptors. Interceptors are used to catch a request or a response and modify it for whatever needs before in gets to it's endpoint. We can use them to collect information about what is coming from the server, store it, and then let response go forward without changes. Since this custom module and spec tests will run on the same page, information about responses can be stored in some global property. Then, when button is clicked, it would be possible to inject custom script to a page to retrieve required responses via browser.executeScript() (docs). Here is the source:
it('should intercept requests', function () {
// Inject custom Angular module on a page
// Script should be injected before you "browser.get()" the page
browser.addMockModule('e2eHttp', function () {
// Note: This function scope is not a Protractor environment
angular
.module('e2eHttp', [])
.config(function ($httpProvider) {
// add custom interceptor to all requests
$httpProvider.interceptors.push('e2eHttpInterceptor');
})
.factory('e2eHttpInterceptor', function () {
return {
response: function (response) {
// name of the global property to store responses
var global = 'e2eHttpResponses';
// responses will be grouped by url
// but you can use data from "response.config" to adapt it
// it has a lot of info about response headers, method, etc
var url = response.config.url;
window[global] = window[global] || {};
window[global][url] = window[global][url] || [];
window[global][url].push(response); // store response
// proceed without changing response
return response;
}
};
});
});
// Load the page
browser.get('#/auth/login');
$('#submit').click();
// If we are sure that response has come, then extract it
browser.executeScript(function () {
// Note: This function scope is not a Protractor environment
var global = 'e2eHttpResponses';
var uri = 'api/auth/login.json';
// extract array of stored responses for required uri
var responses = (window[global] && window[global][uri]) || [];
// return responses to spec
return responses;
}).then(function (responses) {
// and finally, we are now able to get all information we need
// about response, and in your case, save it to a file
console.log(responses);
var data = responses[0].data; // first response body as a string
});
// remove injected module not to break another specs
browser.removeMockModule('e2eHttp');
});
You can move setup and injection calls to some utility modules, so test specs would be clean.
I'm facing the following problem and I can't get rid of it :
I've got an Angular app that calls an API using $http.post,
this api call make an update to the database and wait 10 sec before returning,
on return of the call, a dialogue is open on the browser saying that test is terminated
When I try to test this small app with Protractor, the test ends before the step 3 occurs. This make my test fail because update in database is not always done. During the test, I see the dialogue opening after 10 sec.
Here is some code.
My Angular service doing the call :
$http.post(url, parameters).
success(function (data) {
$log.debug('Success in cldHttp data is "%s"', JSON.stringify(data));
NotifSrv.translateMessage('commons.request.ok', [],
function (successMessage) {
data.errorMessage = null;
if (options.notifySuccess) NotifSrv.addNotification(successMessage, 'success');
if (cb) cb(undefined, data);
});
});
My Protractor test :
browser.get('/#!/activate-account.html?id=' + acc._id).then(function () {
browser.sleep(1000);
// Check that DB is updated
accountColl.findOne({
pseudo: 'MyActivatePseudo'
}, function (err, acc2) {
expect(err).to.not.exist; // OK
expect(acc2.activated).to.be.true; // KO the DB update has been done just after the findOne
});
});
I try the browser.sleep() in the protractor test but it does nothing.
Many thank's for your help because I'm totally stuck!
JM.