Short stack trace with async await in protractor 7 - testing

I'm trying to automate some tests with protractor and jasmine and I'm using async/await to resolve the promises.
The issue is, when an error does happen, the stack trace is TOO short and thus, I can't seem to locate the source of the issue.
I did make sure to put SELENIUM_PROMISE_MANAGER to FALSE in the config file.
I'm using protractor 7 along with node 14.16.0
Does anyone know how to solve this ? There are not enough details
Here's a code snippet
const invoicesButton: Button = new Button("Invoices", LocatorType.Href, "#/Invoices");
describe("Kouka test", function () {
beforeEach(function () {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000000000;
});
it("Does a random test", async function () {
await browser.get("https://appdev.expensya.com/Portal/#/Login?lang=en");
await loginEmailInput.typeText("amr.refacto#yopmail.com")
await loginPasswordInput.typeText("a")
await loginButton.click(true);
await dashboardPage.invoicesButton.click().catch((e) => {
e.stackTraceLimit = Infinity;
throw e;
});
await userInvoicesPage.createManualInvoice(invoice).catch((e) => {
e.stackTraceLimit = Infinity;
console.error("TEST ERROR ", e);
throw e;
});
await browser.sleep(10000);
});
});
And here's the definition of the "Button" Class:
import { browser } from "protractor";
import { WebComponent } from "./webComponent";
export class Button extends WebComponent {
/**
* #param webElementText Text that the web element contains.
* #param locatorType Locator type of the web element to search for.
* #param locator Locator of the web element to search for.
* #param parentElement Parent Web Component if it exists.
*/
constructor(webElementText, locatorType, locator, parentElement: WebComponent = null) {
super(webElementText, locatorType, locator, parentElement);
}
async click(usingJavaScript = false) {
if (usingJavaScript) {
await this.isPresent();
await browser.executeScript("arguments[0].click();", await this.webElement)
}
else {
await this.isVisible();
await this.isClickable();
await this.webElement.click();
}
}
}
Finally, here's the stack trace
Started
Jasmine started
undefined
F
Kouka test
× Does a random test
- Failed: Wait timed out after 10012ms
at C:\Users\Amrou Bellalouna\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2201:17
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
From asynchronous test:
Error
at Suite.<anonymous> (C:\Users\Amrou Bellalouna\source\repos\NewE2EArchitecture\NewArchitecture\koukouTest.spec.ts:20:5)
at Object.<anonymous> (C:\Users\Amrou Bellalouna\source\repos\NewE2EArchitecture\NewArchitecture\koukouTest.spec.ts:15:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
Failures:
1) Kouka test Does a random test
Message:
Failed: Wait timed out after 10012ms
Stack:
TimeoutError: Wait timed out after 10012ms
at C:\Users\Amrou Bellalouna\AppData\Roaming\npm\node_modules\protractor\node_modules\selenium-webdriver\lib\promise.js:2201:17
at runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
From asynchronous test:
Error
at Suite.<anonymous> (C:\Users\Amrou Bellalouna\source\repos\NewE2EArchitecture\NewArchitecture\koukouTest.spec.ts:20:5)
at Object.<anonymous> (C:\Users\Amrou Bellalouna\source\repos\NewE2EArchitecture\NewArchitecture\koukouTest.spec.ts:15:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
1 spec, 1 failure
Finished in 19.461 seconds

I remember trying to solve this a while ago and I couldn't. But I implemented a bunch of workarounds and apparently this was enough
To begin, can you share what these are doing
await this.isPresent();
await this.isVisible();
await this.isClickable();
Having this function
async isVisible(){
await browser.wait(
ExpectedConditions.visibilityOf(this.webElement),
this._elapsedTime
)
}
you can use an advantage of third argument of browser.wait as described here and include an optional message on failure like this
async isVisible(){
await browser.wait(
ExpectedConditions.visibilityOf(this.webElement),
this._elapsedTime,
`Element ${this.webElement.locator().toString()} is not present after ${this._elapsedTime}ms`);
)
}
(I'm giving you all my secret sauce ingredients haha) If you add this to onPrepare in the config
/**
* Set global environment configuration
*/
Object.defineProperty(global, '__stack', {
get: function() {
let orig = Error.prepareStackTrace;
Error.prepareStackTrace = function(_, stack) {
return stack;
};
let err = new Error();
Error.captureStackTrace(err, arguments.callee);
let stack = err.stack;
Error.prepareStackTrace = orig;
return stack;
},
});
// returns name of the file from which is called
Object.defineProperty(global, '__file', {
get: function() {
let path = __stack[1].getFileName();
try {
//*nix OSes
return path.match(/[^\/]+\/[^\/]+$/)[0];
} catch (error) {
//Windows based OSes
return path.match(/[^\\]+\\[^\\]+$/)[0];
}
},
});
// returns function name from which is called
Object.defineProperty(global, '__function', {
get: function() {
return __stack[1].getFunctionName();
},
});
// returns line number of the position in code when called
Object.defineProperty(global, '__line', {
get: function() {
return __stack[1].getLineNumber();
},
});
then you can use it for logging the file name, function name, and the line where it's called
For example,
async isVisible(){
await browser.wait(
ExpectedConditions.visibilityOf(this.webElement),
this._elapsedTime,
`Failed at ${__file} -> ${__function}() -> line ${__line}`
)
}
will result in this error
- Failed: Failed at common/index.js -> isVisible() -> line 82
Wait timed out after 1032ms
Wait timed out after 1032ms
So you can accommodate this to your needs
also I just realized you may want to play around with __stack variable itself

Related

Solidity TypeError: artifacts is not a function

I am a student learning to write smart contracts using solidity. When running these codes using truffle(ganache):
Helloworld.sol
pragma solidity 0.5.12;
contract Helloworld {
string message = "Hello World";
function getMessage() public view returns (string memory) {
return message;
}
function setMessage(string memory newMessage) public payable {
message = newMessage;
}
}
Helloworld_migration.js
const Helloworld = artifacts.require("Helloworld");
module.exports = function(deployer, network, accounts){
deployer.deploy(Helloworld).then(function(instance){
instance.setMessage("Hello Again!", {value: 1000000, from: accounts[0]}).then(function(){
console.log("Success");
}).catch(function(err){
console.log("error: " + err);
});
}).catch(function(err){
console.log("Deploy failed " + err);
});
};
Helloworldtest.js
const Helloworld = artifacts().require("Helloworld");
contract("Helloworld", async function(){
it("should initialize correctly", async function(){
let instance = await Helloworld.deployed();
let message = await instance.getMessage();
assert(message === "Hello Again!");
});
});
I received this error msg:
TypeError: artifacts is not a function
at Object.<anonymous> (/Users/cherrybluemoon/projects/test/Helloworldtest.js:1:20)
at Module._compile (internal/modules/cjs/loader.js:1123:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
at Module.load (internal/modules/cjs/loader.js:972:32)
at Function.Module._load (internal/modules/cjs/loader.js:872:14)
at Module.require (internal/modules/cjs/loader.js:1012:19)
at require (internal/modules/cjs/helpers.js:72:18)
at /usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:231:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles
(/usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:228:14)
at Mocha.run
(/usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:536:10)
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-
core/lib/test.js:135:1
at processTicksAndRejections (internal/process/task_queues.js:97:5)
You have to remove "()" from artifacts.
const Helloworld = artifacts.require("Helloworld");
Helloworld_migration.js is an invalid file name for a migration file. It needs to start with a number such as 1_migration.js or 1_helloworld_migration.js

Asynchronous controller in Express for Form parsing to Mongoose

Currently, I'm developing a way to upload a message (file and fields) from Dropzone to Mongoose using Express Router. My back-end controller (which is called after authentication and data validation) goes as follows:
//Import Internal Dependencies
const Loader = require('../models/loader.js');
const Formidable = require('formidable');
const fs = require('fs');
module.exports = {
load: async (req, res, next) => {
var form = new Formidable.IncomingForm();
let path;
let contentType;
await form.parse(req, async function (err, fields, files) {
if (err) {
return res.status(404).json(err);
} else {
const {
user,
patient,
condition,
compound,
classi
} = fields;
path = files.image.path;
contentType = files.image.type;
fs.readFile(path, async function (err, data) {
if (err) {
return res.status(404).json(err);
} else {
//Save load
const newLoader = new Loader({
user,
patient,
condition,
compound,
classi,
image: {
data,
contentType
}
});
//Delete image in local storage
await fs.unlink(path, function (error) {
if(error){
return res.status(404).json(error)
}
});
await newLoader.save();
res.status(200).json("Load image sucessfully.");
next()
}
})
}
});
}
};
When I test it with Postman I got a status 202 and images are successfully upload to the database. However, when I try to upload with dropzone without the fields (which should cause some error and be displayed in dropzone) I got the following errors/warning in the back-end console (Dropzone stoped at upload and didn't show any error):
(node:20834) UnhandledPromiseRejectionWarning: ValidationError: load validation failed: user: Path `user` is required., classi: Path `classi` is required.
at new ValidationError (/root/aimuneBack/node_modules/mongoose/lib/error/validation.js:27:11)
at model.Document.invalidate (/root/aimuneBack/node_modules/mongoose/lib/document.js:1876:32)
at p.doValidate.skipSchemaValidators (/root/aimuneBack/node_modules/mongoose/lib/document.js:1744:17)
at /root/aimuneBack/node_modules/mongoose/lib/schematype.js:808:9
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
(node:20834) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:20834) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
at emitWarning (internal/process/promises.js:92:15)
at emitPendingUnhandledRejections (internal/process/promises.js:109:11)
at process._tickCallback (internal/process/next_tick.js:189:7)
POST /load - - ms - -
So I know I have done something wrong with my asynchronous code and unfortunately cannot figure it out. Hope you can help. Best regards, Andre

Intermittent Selenium ECONNREFUSED errors on CircleCI

Our CircleCI tests use selenium, via the selenium-webdriver to run UI tests through PhantomJS. The tests work 100% of the time locally in our vagrant env, but fail about 1 out of 3 times on CircleCI with ECONNREFUSED errors like:
Error: ECONNREFUSED connect ECONNREFUSED 10.0.4.1:59525
at ClientRequest.<anonymous> (node_modules/selenium-webdriver/http/index.js:238:15)
at Socket.socketErrorListener (_http_client.js:310:9)
at emitErrorNT (net.js:1278:8)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9)
From: Task: WebDriver.navigate().to(http://127.0.0.1:8080/src/public/login.php?t=ur&ign=1&ut=ad)
at thenableWebDriverProxy.schedule (node_modules/selenium-webdriver/lib/webdriver.js:816:17)
at Navigation.to (node_modules/selenium-webdriver/lib/webdriver.js:1140:25)
at thenableWebDriverProxy.get (node_modules/selenium-webdriver/lib/webdriver.js:997:28)
at User.logIn (testJs/ui/utils/user.js:9:16)
at Host.logInAsHost (testJs/ui/utils/host.js:13:14)
at Preferences.disableRevenueGeneration (testJs/ui/utils/preferences.js:57:14)
at Context.<anonymous> (testJs/ui/tests/preferences.js:13:22)
These errors happen at random times throughout our tests and they are not being triggered by any particular place in our tests. As far as I can tell, this issue is occurring on the selenium/selenium-webdriver end as the web server remains up and working and isn't generating any errors.
I’ve tried all of the following and none of them have worked:
Upgraded to the latest selenium-webdriver (3.4.0)
Upgraded to a more recent version of nodejs (6.9.2)
Used a different web server
Upgraded to a recent version of PhantomJS (1.9.7-15)
Tried using export DBUS_SESSION_BUS_ADDRESS as per
https://github.com/SeleniumHQ/docker-selenium/issues/87
In node_modules/selenium-webdriver/http/index.js, I modified the code to retry for ECONNREFUSED errors by reusing the retry already there for ECONNRESET, i.e. if (e.code === 'ECONNRESET') { becomes if (e.code === 'ECONNRESET' || e.code === 'ECONNREFUSED') {. This doesn’t work as then selenium-webdriver just retries indefinitely and from this I realized that the issue appears to be that once an ECONNREFUSED error is encountered, selenium/selenium-webdriver are unrecoverable.
Has anyone found a solution?
WARNING: This is merely a hack and is by no means a proper solution, but it is the only one that appears to reliably work for us on CircleCI. Hopefully, someone else will find a better solution.
Our test framework, mocha, appears to have a retry mechanism developed specifically for selenium (go figure): http://mochajs.org/#retry-tests. The first gotcha is that code in after and before is not retried. Therefore, you need to move code to beforeEach and afterEach. The second gotcha is that you need some special logic in beforeEach and afterEach to handle driver errors.
So, in order to utilize this mechanism, we had to refactor our tests so that each test has a beforeEach that sets up a fresh webdriver instance and then an afterEach that quits that driver instance. This way, a crashed driver instance doesn’t stop all subsequent tests. We developed a helper function that we call at the beginning of all describe blocks so that we don’t have to add too much code to our tests.
Then, we added this.retries(10) to our topmost describe block.
Here is the helper class:
var webdriver = require('selenium-webdriver');
// We default to using phantomjs, but in the future, when we run tests in other browsers, e.g. via
// SauceLabs, we'll want to change the browser.
var customPhantom = webdriver.Capabilities.phantomjs();
customPhantom.set('ssl-protocol', 'any');
// For convenience in tests
global.By = webdriver.By;
global.until = webdriver.until;
var SeleniumStabilizer = function () {};
SeleniumStabilizer.prototype.MAX_RETRIES = 10;
SeleniumStabilizer.prototype.createDriver = function () {
global.driver = new webdriver.Builder()
// .forBrowser('phantomjs')
.withCapabilities(customPhantom)
.build();
// Resolves when driver is ready
return global.driver;
};
SeleniumStabilizer.prototype.init = function (opts) {
var self = this,
n = 0;
var beforeEachWithRetries = function () {
// Create a fresh selenium driver for the next test
return self.createDriver().then(function () {
if (opts.onBeforeEach) {
// Execute the test-specific defined onBeforeEach
return opts.onBeforeEach();
}
}).catch(function (err) {
// ECONNREFUSED error and we should retry?
if (err.message.indexOf('ECONNREFUSED') !== -1 && n++ < self.MAX_RETRIES) {
return beforeEachWithRetries();
} else {
throw err;
}
});
};
opts.beforeEach(function () {
n = 0;
return beforeEachWithRetries();
});
var afterEachWithRetries = function () {
return Promise.resolve().then(function () {
if (opts.onAfterEach) {
// Execute the test-specific defined onAfterEach
return opts.onAfterEach();
}
}).then(function () {
// Quit the selenium driver before starting the next test
return driver.quit();
}).catch(function (err) {
// ECONNREFUSED error and we should retry?
if (err.message.indexOf('ECONNREFUSED') !== -1 && n++ < self.MAX_RETRIES) {
// Create a new driver
return self.createDriver().then(function () {
return afterEachWithRetries();
});
} else {
throw err;
}
});
};
opts.afterEach(function () {
n = 0;
return afterEachWithRetries();
});
};
Then, your tests look like:
var seleniumStabilizer = new SeleniumStabilizer();
describe('my tests', function () {
this.retries(seleniumStabilizer.MAX_RETRIES);
describe('search engines', function () {
seleniumStabilizer.init({
beforeEach: beforeEach,
afterEach: afterEach,
onBeforeEach: function () {
// e.g. return doPromiseAfterDriverSetUp();
},
onAfterEach: function () {
// e.g. return doPromiseBeforeDriverQuits();
}
});
it('should get google', function () {
return driver.get('https://www.google.com');
});
it('should get amazon', function () {
return driver.get('https://www.amazon.com');
});
});
});

wit.ai quickstart.js error from node, unexpected token{

I am going through the wit.ai quickstart tutorial and get an error from node (version 4.5.0 LTS), but I don't see the error in the code and also, it is the example code downloaded directly from wit.ai:
examples\quickstart.js:39
const {sessionId, context, entities} = request;
SyntaxError: Unexpected token {
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
Also, the code in the download from git is different than the code shown on the tutorial page:
Code from the git clone, example/quickstart.js is this:
'use strict';
let Wit = null;
let interactive = null;
try {
// if running from repo
Wit = require('../').Wit;
interactive = require('../').interactive;
} catch (e) {
Wit = require('node-wit').Wit;
interactive = require('node-wit').interactive;
}
const accessToken = (() => {
if (process.argv.length !== 3) {
console.log('usage: node examples/quickstart.js <wit-access-token>');
process.exit(1);
}
return process.argv[2];
})();
// Quickstart example
// See https://wit.ai/ar7hur/quickstart
const firstEntityValue = (entities, entity) => {
const val = entities && entities[entity] &&
Array.isArray(entities[entity]) &&
entities[entity].length > 0 &&
entities[entity][0].value
;
if (!val) {
return null;
}
return typeof val === 'object' ? val.value : val;
};
const actions = {
send(request, response) {
const {sessionId, context, entities} = request;
const {text, quickreplies} = response;
console.log('sending...', JSON.stringify(response));
},
getForecast({context, entities}) {
var location = firstEntityValue(entities, 'location');
if (location) {
context.forecast = 'sunny in ' + location; // we should call a weather API here
delete context.missingLocation;
} else {
context.missingLocation = true;
delete context.forecast;
}
return context;
},
};
const client = new Wit({accessToken, actions});
interactive(client);
but the tutorial says the const actions section should be this:
const actions = {
send(request, response) {
const {sessionId, context, entities} = request;
const {text, quickreplies} = response;
return new Promise(function(resolve, reject) {
console.log('sending...', JSON.stringify(response));
return resolve();
});
},
getForecast({context, entities}) {
return new Promise(function(resolve, reject) {
// Here should go the api call, e.g.:
// context.forecast = apiCall(context.loc)
context.forecast = 'sunny';
return resolve(context);
});
},
};
Regardless, both versions give the same error.
Turns out that, due to some ECMAScript 6 features in the code, if your node version <= 6.x.x, you have to add the flag harmony_destructuring to the node command line, as illustrated here:
node --harmony_destructuring examples/quickstart.js

How to test an Electron app with selenium webdriver

I have read the documentation and I have followed the tutorial step by step and I only have managed to run the app.
Documentation: http://electron.atom.io/docs/tutorial/using-selenium-and-webdriver/
The connection with chromedriver I cannot make it work, when I launch the test and try click a simple button I get this:
Error: ChromeDriver did not start within 5000ms at Error (native)
at node_modules/spectron/lib/chrome-driver.js:58:25 at
Request._callback (node_modules/spectron/lib/chrome-driver.js:116:45)
at Request.self.callback
(node_modules/spectron/node_modules/request/request.js:200:22) at
Request.
(node_modules/spectron/node_modules/request/request.js:1067:10) at
IncomingMessage.
(node_modules/spectron/node_modules/request/request.js:988:12) at
endReadableNT (_stream_readable.js:913:12) at _combinedTickCallback
(internal/process/next_tick.js:74:11) at process._tickCallback
(internal/process/next_tick.js:98:9)
My code:
"use strict";
require("co-mocha");
var Application = require('spectron').Application;
var assert = require('assert');
const webdriver = require('selenium-webdriver');
const driver = new webdriver.Builder()
.usingServer('http://127.0.0.1:9515')
.withCapabilities({
chromeOptions: {
binary: "./appPath/app"
}
})
.forBrowser('electron')
.build();
describe('Application launch', function () {
this.timeout(100000);
var app;
beforeEach(function () {
app = new Application({
path: "./appPath/app"
});
return app.start();
});
afterEach(function () {
if (app && app.isRunning()) {
return app.stop();
}
});
it('click a button', function* () {
yield driver.sleep(5000);
yield driver.findElement(webdriver.By.css(".classSelector")).click();
});
});
Thanks and sorry for my English.
I recommend you to use Spectron. which is a less painful way of testing your electron app. in my opinion perfect combination is using it with Ava test framework, which allows the concurrently test.
async & await is also another big win. which allows you to have so clean test cases.
and also if you have a test which needs to happen serial, you can use test.serial
test.serial('login as new user', async t => {
let app = t.context.app
app = await loginNewUser(app)
await util.screenshotCreateOrCompare(app, t, 'new-user-mission-view-empty')
})
test.serial('Can Navigate to Preference Page', async t => {
let app = t.context.app
await app.client.click('[data-test="preference-button"]')
await util.screenshotCreateOrCompare(app, t, 'new-user-preference-page-empty')
})
and just for reference; my helper test cases.
test.before(async t => {
app = util.createApp()
app = await util.waitForLoad(app, t)
})
test.beforeEach(async t => {
t.context.app = app
})
test.afterEach(async t => {
console.log('test complete')
})
// CleanUp
test.after.always(async t => {
// This runs after each test and other test hooks, even if they
failed
await app.client.localStorage('DELETE', 'user')
console.log('delete all files')
const clean = await exec('rm -rf /tmp/DesktopTest')
await clean.stdout.on('data', data => {
console.log(util.format('clean', data))
})
await app.client.close()
await app.stop()
})
util function,
// Returns a promise that resolves to a Spectron Application once the app has loaded.
// Takes a Ava test. Makes some basic assertions to verify that the app loaded correctly.
function createApp (t) {
return new Application({
path: path.join(__dirname, '..', 'node_modules', '.bin',
'electron' + (process.platform === 'win32' ? '.cmd' : '')),
// args: ['-r', path.join(__dirname, 'mocks.js'), path.join(__dirname, '..')],
env: {NODE_ENV: 'test'},
waitTimeout: 10e3
})
}
First off, Spectron (which is a wrapper for WebdriverIO) and WebdriverJS (which is part of Selenium-Webdriver) are two different frameworks, you only need to use one of them for your tests.
If you are using WebdriverJS, then you need to run ./node_modules/.bin/chromedriver in this step: http://electron.atom.io/docs/tutorial/using-selenium-and-webdriver/#start-chromedriver
I could get ChromeDriver working by adding a proxy exception in my terminal.
export {no_proxy,NO_PROXY}="127.0.0.1"