I have an XML configured like this
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="SuiteName" verbose="7">
<test name="TestName">
<method-selectors>
<method-selector>
<script language="beanshell">
<![CDATA[
driverType = System.getProperty("driverType");
if (driverType.equals("IOS")){
return groups.containsKey("All") && (!groups.containsKey("wip") && !groups.containsKey("iOS"));
} else {
return groups.containsKey("All") && (!groups.containsKey("wip"));
}
]]></script>
</method-selector>
</method-selectors>
<classes>
<class name="classnameHere"/>
</classes>
</test>
</suite>
Now I have a Jenkins job that sends a command -DsuiteXmlFile=${suiteXmlfile}.xml (i have multiple suites XML files configured)
The tests create reports that contain in name the "suiteXmlFile" param value, but for debug or when I have to run something not form Jenkins I just right click on the XML file but the reporter see suiteXmlFile as empty (obviously).
I tried System.setProperty("suiteXmlFile","suiteName"); (i use this inside methods and works well) but from the XML file it seems it doesn't work. Is there any other way to set that property?
System.setProperty("suiteXmlFile","suiteName") actually works. the problem was that I was trying to read that property before it was set by xml
Related
I've recorded a test using Selenium IDE and am submitting the generated .side file to selenium-side-runner to run on a Selenium Grid built using Zalenium. Is it possible to run a command that calls driver.manage().addCookie() from the test that was submitted to selenium-side-runner? I want to do this to send messages back to Zalenium with test progress and status
I added a command executeScript to the Selenium IDE editor with a target of driver.manage().addCookie({name: 'test', value: 'test'})
I see that the command that selenium-side-runner generated in commons.js was
await driver.executeScript(`driver.manage().addCookie({name:'test', value: 'test'});`);
Doing this causes the browser to report an error JavascriptError: javascript error: driver is not defined
I think what I need is the code to be generated without the driver.executeScript wrapper. Is there a way to accomplish this without exporting my Selenium IDE test to NUnit?
I was able to make this functionality work by crudely modifying the selenium-side-runner package on my Windows dev machine
In file ~\node_modules\selenium-side-runner\node_modules\selianize\dist\selianize.cjs.js
Change
function generateScript(script, isExpression = false) {
return `await driver.executeScript(\`${isExpression ? `return (${script.script})` : script.script}\`${script.argv.length ? ',' : ''}${script.argv.map(n => `vars["${n}"]`).join(',')});`;
}
to
function generateScript(script, isExpression = false) {
if (script.script.indexOf('zalenium') > -1)
{
return script.script;
} else
{
return `await driver.executeScript(\`${isExpression ? `return (${script.script})` : script.script}\`${script.argv.length ? ',' : ''}${script.argv.map(n => `vars["${n}"]`).join(',')});`;
}
}
Now when running a test with selenium-side-runner, calling "executeScript" with any value that contains zalenium will generate the command verbatim in the test script
I have a main feature file where I have included a "setup" feature file that should add some test data. This setup feature file has an annotation that I have called #ignore. However, following the instructions in this Can't be enable to #ignore annotation for the features SO answer, but I am still seeing the setup feature file being run outside of the main test feature.
Main feature file, unsubscribe_user.feature:
Feature: Unsubscribe User
Background:
* def props = read('properties/user-properties.json')
* url urlBase
* configure headers = props.headers
* def authoriZation = call read('classpath:basic-auth.js') { username: 'admin', password: 'admin' }
* def testDataSetup = call read('classpath:com/meanwhileinhell/app/karate/feature/mockserver/testDataSetup.feature') { data1: #(props.data1), data2: #(props.data2) }
Scenario: Unsubscribe user
...
...
Scenario: Remove test data
* def testDataTearDown = call read('classpath:com/meanwhileinhell/app/karate/feature/mockserver/testDataTearDown.feature') { data1: #(props.data1), data2: #(props.data2) }
...
testDataSetup.feature file
#ignore
Feature: Add data to REST Mock Server
Background:
* url mockServerUrlBase
Scenario: Add data
* print 'Adding test data'
Given path 'mapping'
And request { data1: '#(data1)', data2: '#(data2)' }
When method post
Then status 201
Now from my Java runner class, I have added #KarateOptions(tags = "~#ignore").
import org.junit.runner.RunWith;
import com.intuit.karate.KarateOptions;
import com.intuit.karate.junit4.Karate;
import cucumber.api.CucumberOptions;
#RunWith(Karate.class)
#CucumberOptions(features = "classpath:com/meanwhileinhell/app/karate/feature/unsubscribe_user.feature")
#KarateOptions(tags = "~#ignore")
public class KarateTestUnSubscribeUserRunner {
}
However, I can still see my print statement in my setup class being called, and two POSTs being performed. I have also tried running my suite with the following cmd options, but again, still see the feature file run twice.
./gradlew clean test -Dkarate.env=local -Dkarate.options="--tags ~#ignore" --debug
I am following this wrong somewhere? Is there something I can add to my karate-config.js file? I am using Karate version 0.9.0.
Annotations only work on the "top level" feature. Not on "called" features.
If your problem is that the features are being run even when not expected, you must be missing something, or some Java class is running without knowing it. So please follow this process and we can fix it: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
EDIT: I think I got it - please don't mix CucumberOptions, in fact we deprecated it, use only KarateOptions. Even that is not recommended in 0.9.5 onwards and you should move to JUnit 5.
Read the docs: https://github.com/intuit/karate#karate-options
When I updated to version 5.4 I no longer have the option to create a playlist in the "playlists" container, nor to add a track to a playlist already existing in it. In version 5.3 it was working well. I also checked other Music Services on Sonos, same problem. Did anything change in the specifications for User Content Playlists that is not specified in the documentation for Playlist Editing?
This is how I'm adding my User Content container:
$result->mediaCollection[] = array('id'=>'playlists', 'title'=>'My Playlists', 'itemType'=>'favorites', 'containsFavorite'=>true, 'displayType'=>'genreList', 'readOnly'=>false, 'userContent'=>true, 'renameable'=>true, 'albumArtURI'=>PATH.'/img.png');
Edit:
I am using the Android controller (version 5.4, build 29590261) and I am testing on a Play:1 (version 5.4, build 29591030).
I am able to add a song/playlist to an already existing playlist or to a new playlist (by long press on a song to get to the extended metadata, and then "Add Track to 'Service Name' Playlist"), but what I can't figure out how to do is: deleting a playlist, renaming a playlist, and editing songs in a playlist (reorder, delete songs). I don't have a screenshot for version 5.3 but there was an button in the top right corner (three vertical dots) of the playlists container from which one can edit playlists or create new ones (check the screenshots below, from version 5.4). Am I missing something?
Edit 2:
I figured out what is causing the issue. I am using the .wsdl for beta in order to be able to implement Custom Item Display (This is not beta anymore, as I understood from the Adding New SMAPI Features page). When I revert to the normal Sonos.wsdl file from the Sonos Documentation, the info and options button appears again. How can I use Custom Item Display while keeping the info and options button there and all functionalities of playlist editing unchanged?
Note: the Sonos(beta).wsdl was here but it's not available anymore.
Edit 3:
I downloaded the Sonos.wsdl from the Sonos documentation, but I still can't see the button. In order to reproduce the issue, please check the following PHP implementation and Presentation Map XML code:
PHP implementation:
define('BASE_PATH', rtrim("http://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']), '/'));
class SonosAPI
{
public function getMetadata($args)
{
$result = new StdClass();
$result->index = $args->index;
switch($args->id) {
case 'root':
$result->mediaCollection[] = array('id'=>'playlists', 'title'=>'My Playlists', 'itemType'=>'favorites', 'displayType'=>'genreList', 'readOnly'=>false, 'userContent'=>true, 'renameable'=>true, 'albumArtURI'=>BASE_PATH.'/image.png');
$result->count = $result->total = 1;
break;
case 'playlists':
$result->mediaCollection[] = array('id'=>'123', 'title'=>'Title', 'itemType'=>'playlist', 'displayType'=>'genreList', 'canPlay'=>true, 'readOnly'=>false, 'userContent'=>false, 'renameable'=>true, 'albumArtURI'=>BASE_PATH.'/image.png');
$result->count = $result->total = 1;
break;
}
return array('getMetadataResult' => $result);
}
}
$server = new SoapServer("Sonos.wsdl", array('cache_wsdl' => 0)); // disable cache in development
$server->setClass('SonosAPI');
try {
$server->handle();
} catch (Exception $e) {
Log("[ERROR] ".$e->getMessage());
}
?>
Presentation Map file:
<?xml version="1.0" encoding="utf-8" ?>
<Presentation>
<PresentationMap type="DisplayType">
<DisplayType id="genreGrid">
<DisplayMode>GRID</DisplayMode>
</DisplayType>
<DisplayType id="genreList">
<DisplayMode>LIST</DisplayMode>
</DisplayType>
<DisplayType id="genreHero">
<DisplayMode>HERO</DisplayMode>
</DisplayType>
<DisplayType id="genreEditorial">
<DisplayMode>EDITORIAL</DisplayMode>
</DisplayType>
<DisplayType id="twoLine">
<Lines>
<Line token="title"/>
<Line token="summary"/>
</Lines>
</DisplayType>
</PresentationMap>
</Presentation>
XML response to getMetadata of root (which contains the playlists container):
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns1="http://www.sonos.com/Services/1.1" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns1:getMetadataResponse>
<ns1:getMetadataResult>
<ns1:index>0</ns1:index>
<ns1:count>4</ns1:count>
<ns1:total>4</ns1:total>
<ns1:mediaCollection>
<ns1:id>rootlang:ar</ns1:id>
<ns1:itemType>collection</ns1:itemType>
<ns1:displayType>genreGrid</ns1:displayType>
<ns1:title>Arabic</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
<ns1:mediaCollection>
<ns1:id>rootlang:en</ns1:id>
<ns1:itemType>collection</ns1:itemType>
<ns1:displayType>genreGrid</ns1:displayType>
<ns1:title>International</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
<ns1:mediaCollection>
<ns1:id>rootlang:default</ns1:id>
<ns1:itemType>collection</ns1:itemType>
<ns1:displayType>genreGrid</ns1:displayType>
<ns1:title>Arabic + International</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
<ns1:mediaCollection renameable="true" readOnly="false" userContent="true">
<ns1:id>playlists</ns1:id>
<ns1:itemType>favorites</ns1:itemType>
<ns1:displayType>genreList</ns1:displayType>
<ns1:title>My Playlists</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
</ns1:getMetadataResult>
</ns1:getMetadataResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML response to getMetadata of playlists:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns1="http://www.sonos.com/Services/1.1" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns1:getMetadataResponse>
<ns1:getMetadataResult>
<ns1:index>0</ns1:index>
<ns1:count>1</ns1:count>
<ns1:total>1</ns1:total>
<ns1:mediaCollection renameable="true" readOnly="false" userContent="false">
<ns1:id>playlist:19663408</ns1:id>
<ns1:itemType>playlist</ns1:itemType>
<ns1:displayType>genreList</ns1:displayType>
<ns1:title>Test Playlist</ns1:title>
<ns1:canPlay>true</ns1:canPlay>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
</ns1:getMetadataResult>
</ns1:getMetadataResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Custom Display Types were made available in the most recent production software update. The beta wsdl that you were using is for v5.4 which is now the current production build. Make sure that you are using the production version of the wsdl and you will have info & options and also have access to Custom Display Types (provided they are properly enabled in your service).
However I have confirmed that we do have a bug when using Display Types with playlist containers when playlist editing is enabled. The work around is to removed the displayType node from your root playlist and child playlist containers (all other containers that use displayType do not need to be changed). This work around has been tested and works. We have opened an issue to track this internally.
This is similar to the question asked here, but that question was not exactly answered to what the problem is.
Customer.xml
<?xml version="1.0" encoding="UTF-8"?>
<wl:adapter name="Customer"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wl="http://www.ibm.com/mfp/integration"
xmlns:http="http://www.ibm.com/mfp/integration/http">
<displayName>Customer</displayName>
<description>Customer</description>
<connectivity>
<connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
<protocol>https</protocol>
<domain>kenatibm.cloudant.com</domain>
<port>443</port>
</connectionPolicy>
</connectivity>
<procedure name="addCustomer"> </procedure>
</wl:adapter>
Customer-impl.js
function addCustomer(param1) {
var input = {
method : 'PUT',
returnedContentType : 'json',
path : 'userInputRequired',
body : {
contentType: 'application/json',
content : param1
}
};
return WL.Server.invokeHttp(input);
}
The issue is that even though I have defined the method as a PUT, when testing using File Run As | Call MobileFirst Adapter the user interface only displays a GET method, there is no option for PUT.
So is the answer that the GET will actually do a PUT or is this a bug or is there a configuration parameter that I am missing?
I think you are confusing how you invoke/test the adapter, with what verb it uses on the back-end system it is calling. You are testing/invoking it using GET, but the adapter is then calling your backend system - http://kenatibm.cloudant.com/backendsystem - using PUT.
This is broadly the same explanation as Dave gave in your previous question.
In short, the answer is that the GET will actually do a PUT.
Parameters are passed to the adapter in a GET request and then the adapter constructs a PUT request to perform the actual procedure. In your code, you can see how the 'param1' is passed by the wizard to the function and then it is set to as the 'content' of the PUT request. It's definitely a little confusing.
I am trying to make an LDAP authentication system using IBM Worklight Studio 6.2.0.01
The login system works fine, no problem with that part, but the logout function doesn't actually log out the user!
Realm:
<realm loginModule="LDAPLoginModule" name="LDAPRealm">
<className>com.worklight.core.auth.ext.FormBasedAuthenticator</className>
</realm>
LoginModule:
<loginModule name="LDAPLoginModule">
<className>com.worklight.core.auth.ext.LdapLoginModule</className>
<parameter name="ldapProviderUrl" value="<Correct LDAP URL ( For security left blank on stackoverflow )>"/>
<parameter name="ldapTimeoutMs" value="2000"/>
<parameter name="ldapSecurityAuthentication" value="simple"/>
<parameter name="validationType" value="exists"/>
<parameter name="ldapSecurityPrincipalPattern" value="{username}"/>
</loginModule>
SecurityTest:
<customSecurityTest name="LDAPSecurityTest">
<test realm="wl_directUpdateRealm" step="1"/>
<test isInternalUserID="true" realm="LDAPRealm"/>
</customSecurityTest>
AdapterXML (important part)
<procedure name="getUsername" securityTest="LDAPSecurityTest" />
<procedure name="onLogout" />
AdapterJS
function getUsername(){
return {username: ""};
}
function onLogout(){
WL.Server.setActiveUser("LDAPRealm", null);
}
The getUsername function gets called everytime the app wants to check if a user is currently logged in, it has NO function other than that.
The logout function (App-side)
$scope.setUsername = function(){
var invocationData = { adapter: "DummyAdapter", procedure: "getUsername"}
WL.Client.invokeProcedure(invocationData, {
onSuccess: function(result){},
onFailure: function(result){);
}
$scope.logout = function(){
WL.Client.logout("LDAPRealm", {onSuccess: $scope.setUsername});
}
Result: This makes the app go to the login page by noticing the user has logged out, only problem is.. it hasn't completely logged out the user. What can I do to make the user completely logged out?
PS: Why don't I use WL.Client.reloadApp after WL.Client.logout()? Two reasons:
White screen and reloading the whole app is just dirty, it's not user friendly at all.
WL.Client.reloadApp gives a fatal signal 11 ( code 1 ) on Android Lollipop ( Android 5.0 ). At least, this is with my worklight version (6.2.0.01).
Please, is there a way I can avoid WL.Client.reloadApp and still log out the user from the server? If not: What may cause the fatal signal 11 ( code 1 ) error in Android Lollipop? I've tested it thoroughly on iOS 8.0, Android 2.3.5, Android 4.4.2 and Android 5.0. Only one that fails is the 5.0
Thank you and sorry for the long post
I have fixed the problem by removing the WL.Client.reloadApp function from logout onsuccess, I did this as such:
$scope.logout = function(){
WL.Client.logout("LDAPRealm", {onSuccess: function(){
$scope.setUsername() // <-- this function is the secret function
// that triggers the securitytest
// which then gives back the login page because
// you had just logged out :)
}});
}
As for the adapter not logging out the user: This comment was false, this bug was originating from another problem. So my code which was posted on StackOverflow was fine. But still:
Android 5.0 and WL.Client.reloadApp don't go to well (5th November 2014 in case an update fixes this)