I was building an automation framework with javascript(VanillaJS), jasmine, and protractor. I chose the log4js with log4js-protractor-appender for the logging. I try to save logs(by browser type) when I perform cross-browser testing. I wanted to run the specs on safari and chrome then expecting to have 2 separate log files for each browser.
Q: How to create two separate log files where one of them contains only log of chrome, the second file contains only logs of safari browser by using technologies mentioned before?
Here is the log4js code from the conf.js file
beforeLaunch : function(){
log4js.configure({
appenders: {
out: { type: 'console' },
result: { type: 'dateFile', filename: 'logs/result',"pattern":"-dd.log", alwaysIncludePattern:true},
error: { type: 'dateFile', filename: 'logs/error', "pattern":"-dd.log", alwaysIncludePattern:true},
default: { type: 'dateFile', filename: 'logs/default', "pattern":"-dd.log", alwaysIncludePattern:true}
},
categories: {
default: { appenders: ['out','default'], level: 'info' },
result: { appenders: ['result'], level: 'info' },
error: { appenders: ['error'], level: 'error' }
}
});
},
onPrepare : function() {
browser.logger = log4js.getLogger('protractorLog4js');
}
The expected result is to have 2 files: default_chrome.log & default_safari.log
// obtain browser name
browser.getBrowserName = function() {
return browser.getCapabilities().then((caps) => {
browser.browserName = caps.get('browserName');
}
)}
// resolve the promised so the browser name is obtained.
browser.getBrowserName();
log4js.configure({
appenders: {
out: { type: 'console' },
default: { type: 'dateFile', filename: 'logs/default_'+ browser.browserName, "pattern":".log", alwaysIncludePattern:true}
},
categories: {
default: { appenders: ['out','default'], level: 'info' }
}
});
I tried this option too:
var browName = () => {return browser.getCapabilities().then((caps) => {caps.get('browserName');});}
I can't provide a ready-to-use answer, because it'll require to have your setup locally, but I can give you directions to look in...
According to https://github.com/angular/protractor/blob/master/lib/config.ts, beforeLaunch is called once per execution (once for all browsers), whereas onPrepare is called for each browser instance and should be used for configuring your logger. So everything related to logger should go to onPrepare
Related
I am learning how to use Playwright coming from a Selenium and Cypress background and testing out the tool to see how it performs on a simple test:
test.describe('IMDB:', () => {
const movieName = 'Forrest Gump';
await page.goto('https://www.imdb.com/');
await page.fill('#suggestion-search', movieName);
expect(await page.textContent('data-testid=search-result--const')).toContain(movieName);
});
});
It simply goes to IMDB, searches for a movie, and then asserts the movie is found.
I have also created a config file in which I have defined that I want to use multiple browsers:
const config: PlaywrightTestConfig = {
timeout: 30000,
use: {
headless: false
},
projects: [
{
name: 'Desktop Chromium',
use: {
browserName: 'chromium',
viewport: { width: 1280, height: 720 },
},
},
{
name: 'Desktop Firefox',
use: {
browserName: 'firefox',
viewport: { width: 1280, height: 720 },
}
},
{
name: 'Mobile Chrome',
use: devices['Pixel 5'],
},
],
};
export default config;
However, when I run the test, due to the search bar being hidden behind a button on the mobile site. The Mobile Chrome test fails.
Is there a way I can do conditional testing to say if a particular device is being used, perform an extra step?
you can access browserName from test() by doing
import { test, expect } from '#playwright/test'
test('Your test', async ({ page, browserName }) => {
if (browserName === 'webkit') {
// Do Something
// Rest of the test code
})
But in your case, it looks like you want to skip the test if it's a mobile viewport, so you can use the test. skip() take a look here: https://playwright.dev/docs/api/class-test#test-skip-2
There is a nice example how Rollup function could be called via MS CRM WebApi here.
But it covers general access to CRM WebApi. Although in most recent versions new JS namespace Xrm.WebApi was introduced. Which provides more straightforward way to access that endpoint.
Method Xrm.WebApi.execute should be able to execute Rollup request, as it is able to execute WhoAmI. But I'm struggling to figure out correct values of parameters to make this execution happen.
Here is my code:
var RollupRequest = function(entityType, id, query) {
this.Target = { entityType: entityType, id: id };
this.RollupType = "Related";
this.Query = {
Query: query
};
};
RollupRequest.prototype.getMetadata = function() {
return {
boundParameter: null,
parameterTypes: {
Target: {
typeName: "Microsoft.Xrm.Sdk.EntityReference",
structuralProperty: 5
},
RollupType: {
typeName: "Microsoft.Dynamics.CRM.RollupType",
structuralProperty: 3
},
Query: {
typeName: "Microsoft.Xrm.Sdk.Query.FetchExpression",
structuralProperty: 5
}
},
operationType: 1, // This is a function. Use '0' for actions and '2' for CRUD
operationName: "Rollup"
};
};
var request = new RollupRequest(
"contact",
"0473FD41-C744-E911-A822-000D3A2AA2C5",
"<fetch><entity name='activitypointer'></entity></fetch>"
);
Xrm.WebApi.execute(request).then(
function(data) {
console.log("Success: ", data);
},
function(error) {
console.log("Failure: ", error);
}
);
The code generates following URL:
/api/data/v9.0/Rollup(Target=#Target,RollupType=#RollupType,Query=#Query)?#Target={"#odata.id":"contacts(0473FD41-C744-E911-A822-000D3A2AA2C5)"}&#RollupType=&#Query={"Query":"<fetch><entity name='activitypointer'></entity></fetch>"}
and the error: "Expression expected at position 0 in ''."
Which, seems to be, indicates that RollupType was not set correctly, because indeed in URL RollupType is missing.
I assume there are more than one potential error, because I'm using FetchXML as query expression. But meanwhile is it possible indicate what should be changed to generate proper URL at least for RollupType property?
I'm building some e2e test for my Vuejs application.
The framework I'm using is Nightwatch along with the http library Axios (and the relative plugin for mocking: Axios-mock-adapter) and my current process is to have a file that intercepts all the api, and a file that return the reponse object:
So for example, if I want to mock /api/sources:
mock.onGet(/my.url\/api\/sources/).reply(() =>
[200, ResponseObject.getSources],
);
And in the reponse object file I have:
const getSources = {
files: [
{
id: 'bogus',
fileName: 'bogus',
fileUrl: 'http://bogus.com/1',
size: 400,
uploadedTime: '2018-05-24 10:56:27',
sourceContact: 'boguscontact',
isFolder: false,
}, {
id: 'bogus2',
fileName: 'bogus 2',
fileUrl: 'http://bogus.com/2',
size: 500,
uploadedTime: '2018-05-24 10:56:27',
sourceContact: 'boguscontact',
isFolder: false,
}, {
id: 'bogus3',
fileName: 'bogus 3',
fileUrl: 'http://bogus.com/3',
size: 600,
uploadedTime: '2018-05-24 10:56:27',
sourceContact: 'boguscontact',
isFolder: false,
},
],
};
With this set up I have a very annoying problem:
Sometimes I have to return different object through the same api call, for example, if the file has a property ready and I want to test the user-flow to prepare a file to be ready I need to return the file with ready: false the first time, then I add some parameters, and then I have to return the file with ready: true. How can I do that?
Another example would be getting a single source file. I have the same api call api/source/:sourceId but when the source has ready: true it needs to have more parameters compare if the source has ready: false, but I don't know how to simulate that behaviour without a backend.
Right now the only thing I can do is to have a different response based on the query parameters:
mock.onGet(/dmd\.mocked\/api\/files/).reply((config) => {
if (typeof config.params !== 'undefined') {
switch (config.params.status) {
case 'queued':
return [200, ResponseObject.queuedFilesList];
case 'processing':
return [200, ResponseObject.processingFilesList];
default:
return [506];
}
} else {
return [200, ResponseObject.queuedFilesList];
}
});
but this approach works only if I make the call with different parameters. If I make the call without any parameters I don't know how to diversify the response.
I'm using nightwatch-cucumber module, which works pretty great,
but I can't save any screenshot in my testing step.
nightwatch.config.js
...
test_settings: {
default: {
screenshots : {
enabled : true,
on_failure : true,
path: 'screenshots/'
},
...
step.js
...
return pageObj
.submit()
.waitForElementVisible('#status')
.getText('#status')
.saveScreenshot('./screenshots')
.expect.element('#status').text.to.contain(status);
...
console error
TypeError: pageObj.submit(...).waitForElementVisible(...).getText(...).saveScreenshot is not a function
any suggestion?
Use this one in the command section. In page object file.
const commands = {
saveScreenshot(filePath) {
this.api.saveScreenshot(filePath);
return this;
}
module.exports = {
url: 'url',
commands: [commands],
elements: {
.......
}
};
}
I'm using Jasmine, Karma, and PhantomJS to automate my tests, but I'm hitting a problem: Phantom doesn't seem to parse my JS correctly. For example, I'm using this mock:
var App = function() {
return {
pageController : {
currentPage : {
on : function() {},
toJSON : function() {},
get : function() {
return dark;
}
}
},
mainLayout : {
header : {
show : function() {},
$el : {}
}
}
};
};
console.log("in test", App());
...which logs out as:
PhantomJS 1.9 (Mac) LOG: [ 'in test',
{ pageController: {},
mainLayout: { header: [Object] } } ]
app.pageController has been emptied here, which causes my tests to fail. Why is this happening & how I can fix it?
The problem seems directly related to the function definitions. For example:
console.log("this is a function:", function() { return 'wat'; });
yields
PhantomJS 1.9 (Mac) LOG: [ 'this is a function:', null ]
The error also occurs in Chrome. It squashes created jasmine spies as well, so I'm guessing it's to do with Karma?
Karma's logging reports all functions as null. (Tests were failing for unrelated reasons).