I'm having a really weird issue with my protractor test. I'm trying to set the right credentials directly on the sessionStorage, but the authentication service doesn't pick up on it. I've isolated it to the following script:
describe('The search', () => {
beforeAll(() => {
browser.executeScript(() => {
window.sessionStorage.setItem('something', JSON.stringify({"test":"test"}));
});
});
it('works when changing URL', () => {
var result1 = browser.executeScript('return window.sessionStorage.getItem(\'something\')');
browser.get('/');
var result2 = browser.executeScript('return window.sessionStorage.getItem(\'something\')');
expect(result1).toBe(result2);
});
});
The output:
1) The search works when changing URL
Message:
Expected '{"test":"test"}' to be null.
Stack:
Error: Failed expectation
at Object.<anonymous> (/source/search.spec.ts:12:25)
at process._tickCallback (node.js:368:9)
So as you can see, as soon as browser.get() is called, the sessionStorage is cleared. Does anyone have any idea on why this could be happening?
Navigating to the URL and then setting the local storage item worked for me:
describe('The search', function () {
var value = JSON.stringify({"test":"test"});
beforeAll(function () {
browser.get('/');
browser.executeScript(function (value) {
window.sessionStorage['something'] = value;
}, value);
});
it('works when changing URL', function () {
var result = browser.executeScript('return window.sessionStorage.getItem(\'something\');');
expect(value).toEqual(result);
});
});
Related
I am using converse.js 7.0.6 version. I am trying to set the subject topic button to be by default hidden, currently, it is visible by default. I have investigated I need to override this function toggleSubjectHiddenState, when I try to use _converse.api.user. I get an error TypeError: Cannot read properties of undefined (reading 'user')
This is how I tried, maybe I am doing wrong something.
export const addModifyHideTopicPlugin = () => {
window.converse.plugins.add('modify-hide-topic', {
overrides: {
ChatRoom: {
toggleSubjectHiddenState: async function () {
const _converse: any = this;
// const muc_jid = this.get('jid');
const jids = await _converse.api.user.settings.get(
'mucs_with_hidden_subject',
[],
);
return _converse.toggleSubjectHiddenState
.apply(_converse, arguments)
.then((response: any) => {
console.log(response, 'response');
return response;
});
},
},
},
});
};
This is the toggleSubjectHiddenState function I am trying to override because this function is handleing the show topic or hide topic.
async toggleSubjectHiddenState () {
const muc_jid = this.get('jid');
const jids = await api.user.settings.get('mucs_with_hidden_subject', []);
if (jids.includes(this.get('jid'))) {
api.user.settings.set('mucs_with_hidden_subject', jids.filter(jid => jid !== muc_jid));
} else {
api.user.settings.set('mucs_with_hidden_subject', [...jids, muc_jid]);
}
},
I am using Protractor and Jasmine to test my hybrid mobile app, which works fine. I'd like to create an incident on my Team Foundation Server (TFS), when a test fails. Therefore, I have to send an REST-Call to the Api, which also works fine in my Angular App. But it does not work, when I am inside my test environment.
My Code:
var BrowsePage = require('./browse.page');
var tfsIncident = require('./tfsIncident_service');
var request = require('request');
describe('Testing the browse state', function () {
var browsePage = new BrowsePage();
var specsArray = [];
var reporterCurrentSpec = {
specDone: function (result) {
if (result.status === 'failed') {
var mappedResult = tfsIncident.create(result);
console.log(mappedResult); //This works so far, but then it crashes
var options = {
method: 'PATCH', //THis Method requiered the API
url: 'MY_COOL_API_ENDPOINT',
headers: {
'Authorization': 'Basic ' + btoa('USERNAME' + ':' + 'PASSWORD'),
'Content-Type': 'application/json-patch+json'
},
body: mappedResult
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body);
console.log(response);
console.log(info);
}
}
request(options, callback);
}
}
};
jasmine.getEnv().addReporter(reporterCurrentSpec);
//This test passes
it('should be able to take display the heading', function () {
expect(browsePage.headline.isPresent()).toBe(true);
});
// Test is supposed to fail
it('should be able to fail', function () {
expect(browsePage.headline).toBe(1);
});
// Test is supposed to fail as well
it('should be able to fail too', function () {
expect(browsePage.headline).toBe(2);
});
});
So the problem is, that my only console output is (after the console.log(mappedResult)): E/launcher - BUG: launcher exited with 1 tasks remaining
So I have no idea, why this does not work.
Any help appreciated.
Edit
Protractor: 5.0.0
Appium Desktop Client: 1.4.16.1
Chromedriver: 2.27
Windows 10 64 Bit
Jasmine: 2.4.1
I finally got my problem solved. The problem was caused by ignoring the promises by jasmine. I had to add a .controllFlow().wait() to my protractor.promise
The following code works fine:
var BrowsePage = require('./browse.page');
describe('Testing the browse state', function () {
var browsePage = new BrowsePage();
var reporterCurrentSpec = {
specDone: function (result) {
if (result.status === 'failed') {
//Mapping of the result
var incident = [
{
op: 'add',
path: '/fields/System.Title',
value: 'Test: ' + result.fullName + ' failed'
},
{
op: 'add',
path: '/fields/System.Description',
value: result.failedExpectations[0].message
},
{
op: 'add',
path: '/fields/Microsoft.VSTS.Common.Priority',
value: '1'
},
{
op: 'add',
path: '/fields/System.AssignedTo',
value: 'Name Lastname <e#mail.com>'
}
];
protractor.promise.controlFlow().wait(create(incident)).then(function (done) { //The magic happens in this line
console.log("test done from specDone:" + done);
});
}
}
};
jasmine.getEnv().addReporter(reporterCurrentSpec); //Add new Jasmine-Reporter
function create(incident) {
var request = require('request');
var defer = protractor.promise.defer(); //new promise
request({
url: 'https://MY_COOL_ENDPOINT.COM',
method: "PATCH",
json: true, // <--Very important!!!
headers: {
'Authorization': 'Basic ' + new Buffer('USERNAME' + ':' + 'PASSWORD').toString('base64'),
'Content-Type': 'application/json-patch+json'
},
body: incident
}, function (error, response, body) {
console.log(error);
console.log(response.statusCode);
console.log(body.id); //Id of created incident on TFS
defer.fulfill({
statusCode: response.statusCode
}); //resolve the promise
});
return defer.promise; //return promise here
}
it('should be able to display the heading', function () {
expect(browsePage.headline.isPresent()).toBe(true);
});
it('should be able to fail', function () {
expect(browsePage.headline.isPresent()).toBe(false);
});
it('should be able to fail 2', function () {
expect(browsePage.headline.isPresent()).toBe(false);
});
});
Attention
When the test suite is done and the last promise is not resolved at this moment, the last incident is not created. I'll try to work around by adding to the last test a browser.sleep(5000); so that the create(incident) function gets more time to finish.
Thanks to this StackOverflow answer for helping me.
User flow: Search for a case >> Search for an item within that case >> expect returned number of results matches value
describe('Search', function () {
beforeEach(function () {
loginPage.signIn();
loginPage.login(username, password);
});
afterEach(function () {
homePage.logOut();
});
it('alecxes suggestion code', function () {
var presenceOfAll = function(elementArrayFinder) {
return elementArrayFinder.count().then(function (count) {
return count > 0;
});
};
homePage.searchForCase(test_case);
filterSearchMenu.searchWithinCase(search_argument);
var hits = element.all(by.binding('response.hits.total'));
browser.wait(presenceOfAll(hits), TIMEOUT);
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
});
});
This fails with expected 4 but was 0
describe('Search', function () {
searchResultTotal = element(by.binding('response.hits.total'));
beforeEach(function () {
loginPage.signIn();
loginPage.login(username, password);
});
afterEach(function () {
homePage.logOut();
});
it('should be able to search', function () {
homePage.searchForCase(test_case);
filterSearchMenu.searchWithinCase(search_argument);
browser.wait(EC.visibilityOf(searchResultTotal), TIMEOUT).then(function () {
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
});
});
});
This works but comes back with a warning that more then one element found for locator by.binding('response.hits.total').
describe('Search', function () {
beforeEach(function () {
loginPage.signIn();
loginPage.login(username, password);
});
afterEach(function () {
homePage.logOut();
});
it('should be able to search', function () {
homePage.searchForCase(test_case);
filterSearchMenu.searchWithinCase(search_argument);
browser.wait(EC.visibilityOf(element.all(by.binding('response.hits.total')).first()), TIMEOUT).then(function () {
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
});
});
});
This Fails and throws an index out of bounds.
Second set of eyes and any help would be appreciated.
You can also solve it with a custom Expected Condition that would check if there are more than 0 elements matching a locator found:
var presenceOfAll = function(elementArrayFinder) {
return elementArrayFinder.count().then(function (count) {
return count > 0;
});
};
var hits = element.all(by.binding('response.hits.total'));
browser.wait(presenceOfAll(hits), TIMEOUT);
expect(element.all(by.binding('response.hits.total')).count()).toEqual(4);
I'm thinking visibilityOf doesn't like multiple elements. Try:
browser.wait(EC.visibilityOf(element.all(by.binding('response.hits.total')).first()), TIMEOUT);
I was making some changes to the page objects we use for running our Protractor tests to run on Sauce Labs i.e., calling a utility method to get browser and platform so we can use the appropriate test user, and after making the change I kept getting a NoSuchElementError when running the test suite.
When I isolate the logout test, it passes, but when run in conjunction with any other files, it fails. Currently, I'm only running the login test and logout test on Chrome to limit the possible causes.
We use page objects to navigate to a testable state, in this case a login page object and a dashboard page object (logging in takes you to the dashboard).
The login page object:
'use strict';
var TestUtils = require('../../util/test-utils.js');
var HeaderPageElement = require('../page_elements/header-page-element.js');
var LoginPage = function () {
var self = this;
this.get = function () {
browser.get('http://localhost:9000/index.html');
this.header = new HeaderPageElement();
this.loginForm = element(by.name('loginForm'));
this.usernameInput = element(by.model('credentials.username'));
this.passwordInput = element(by.model('credentials.password'));
this.loginButton = element(by.name('loginButton'));
this.signupLink = element(by.xpath('//a[#ui-sref="signup"]'));
};
this.setCredentials = function (username, password) {
var deferred = protractor.promise.defer();
var testUtils = new TestUtils();
testUtils.getCapabilities().then(function (capabilities) {
return testUtils.getTestUser(capabilities.browserName, capabilities.platform);
}).then(function (testUser) {
username = username || testUser.username;
password = password || testUser.password;
self.usernameInput.sendKeys(username);
self.passwordInput.sendKeys(password);
deferred.fulfill();
});
return deferred.promise;
};
this.login = function (username, password) {
return this.setCredentials(username, password).then(function () {
return self.loginButton.click();
});
};
this.signup = function () {
return this.signupLink.click();
};
this.get();
};
module.exports = LoginPage;
The dashboard page object:
'use strict';
var LoginPage = require('./login-page.js');
var HeaderPageElement = require('../page_elements/header-page-element.js');
var ProjectCreateModalPageElement = require('../page_elements/project-create-modal-page-element.js');
var DashboardPage = function () {
var self = this;
this.get = function () {
var loginPage = new LoginPage();
loginPage.login();
this.header = new HeaderPageElement();
this.newProjectButton = element(by.name('newProjectButton'));
this.projectFilterInput = element(by.name('projectFilterInput'));
};
this.createNewProject = function (projectTitle, projectTypes) {
var deferred = protractor.promise.defer();
this.newProjectButton.click().then(function () {
var modalPage = new ProjectCreateModalPageElement();
modalPage.createNewProject(projectTitle, projectTypes);
deferred.fulfill();
});
return deferred.promise;
};
this.get();
};
module.exports = DashboardPage;
These are the tests that are being run.
The login test:
'use strict';
var LoginPage = require('./pages/login-page.js');
describe('login test', function () {
var page;
beforeEach(function () {
page = new LoginPage();
});
it('should be directed to login', function () {
expect(page.loginForm.isPresent()).toBe(true);
});
it('Login button should be disabled', function () {
expect(page.loginButton.getAttribute('disabled')).toEqual('true');
page.setCredentials('wrong', 'user').then(function () {
expect(page.loginButton.getAttribute('disabled')).toEqual(null);
});
});
it('login should fail and remain at login screen', function () {
page.login('wrong', 'user').then(function () {
expect(page.loginForm.isPresent()).toBe(true);
});
});
it('login success should redirect to dashboard', function () {
page.login().then(function () {
browser.wait(function () {
return $('#dashboard').isPresent();
});
expect($('#dashboard').isDisplayed()).toBe(true);
});
});
});
The logout test:
'use strict';
var DashboardPage = require('./pages/dashboard-page.js');
describe('logout test', function () {
var page;
beforeEach(function () {
page = new DashboardPage();
});
it('logout success should redirect to login page', function () {
page.header.logout().then(function() {
browser.wait(function () {
return $('#login').isPresent();
});
expect($('#login').isDisplayed()).toBe(true);
});
});
});
The error I get when running these tests sequentially is as follows:
NoSuchElementError: No element found using locator: by.model("credentials.username")
The line it specifies is the get method inside the DashboardPage object, whereby it instantiates a LoginPage object and calls the login method so as to navigate to the dashboard:
this.get = function () {
var loginPage = new LoginPage();
loginPage.login();
this.header = new HeaderPageElement();
this.newProjectButton = element(by.name('newProjectButton'));
this.projectFilterInput = element(by.name('projectFilterInput'));
};
For whatever reason, the usernameInput of the login page hasn't been set by the time the login method is called.
I'm quite sure it's got something to do with not having coded promises correctly, but I've been bashing my head against it for days without any success. Any help would be greatly appreciated.
I'm trying to use protractor to make e2e tests for one of our pages.
The pages are run in an iframe of a surrounding system.
So to be able to test my page I have to do all the things before "it ('Overview opened...". I'm not saying I have to do them in the way I have done. If there is a better way, please tell me.
Now my problem is that "errandClose is run before the tests in "Overview opened".
Have I done something wrong or misunderstood how protractor works.
describe('toplevel test', function() {
var login = new loginPage();
var role = new roleSelectionPage();
var errand = new overViewAndErrand(login.getBaseUrl());
beforeEach(function() {
login.getPage(); //Goes to login page and logs in
});
it('should log in', function () {
expect(element(by.model("therole")).isDisplayed());
describe('Select role', function() {
beforeEach(function () {
role.selectRole(); //Selects role on page after login and ends up at next page
});
it('Role selected', function() {
expect(element(by.css('a[href*="/OverviewNext"]')) !== undefined);
describe('Open overview', function() {
beforeAll(function() {
errand.open('name of errand'); //Selects errand and clicks on button, iframe i opened
});
afterEach(function() {
errand.close(); // Leaves the iframe and clicks on remove errand
});
it ('Overview opened', function() {
describe('Test form', function() {
browser.sleep(5000);
it ('test', function() {
browser.sleep(500);
element(by.model("modelvalue")).sendKeys('Ture Trana').then(function() {console.log('Ture Trana')});
});
});
});
});
});
});
});
});
As a response to the flat question.
How I would like to be able to run my tests is something like this
login.getPage();
role.select('role1');
errand.create();
begin
test 1
...
test n
end
errand.save();
role.select(role 2);
errand.open(previous errand);
begin
test 1
...
test n
end
login.logout();
Where all the selectRole, createErrand, openErrand involves going to at least one page and clicking on some buttons and selecting in lists.
You shouldn't nest describe() within it().
You should close this test before you start a new one
Example: This should be closed before you start a new describe.
it('Role selected', function() {
expect(element(by.css('a[href*="/OverviewNext"]')) !== undefined);
Here is an example with nested describes, that works for me.
describe('overview page', () => {
let hostUrl = configMock[0].response.data.URL;
beforeAll(() => {
//do magic
});
describe('all statement cards', () => {
beforeAll(() => {
browser.get(`${hostUrl}/z/y/1/g`);
browser.waitForAngular();
});
describe('Campaign overview', () => {
beforeEach(() => {
//before each magic
});
it('has correct data for Delivered', () => {
expect(delivered.getText()).toEqual('1.6k');
});
});
});
});
Starting from this, I think you can adapt it to your needs.