I'm launching native apps with the help of WebdriverIO and mocha, but unable to communicate with the device, but able to launch the application but not interact with the element.
android_app_test.js
const webdriverio = require('webdriverio');
const androidOptions = require('../../../helpers/caps').androidOptions;
const assert = require('chai').assert;
androidOptions.capabilities.appPackage = "com.google.android.calculator"
androidOptions.capabilities.appActivity = "com.android.calculator2.Calculator"
describe('Create Chrome web session', function () {
let client;
before(async function () {
client = await webdriverio.remote(androidOptions)
});
after(async function () {
await client.deleteSession();
});
it('should create and destroy Android browser session', async function () {
const elem = await $('#digit_2')
elem.waitForDisplayed(3000);
await client.touchClick('digit_2');
});
});
config.js
var Mocha = require('mocha'), fs = require('fs');
var mocha = new Mocha({
reporter: 'mochawesome-screenshots',
reporterOptions: {
reportDir: 'customReportDir',
reportName: 'customReportName',
reportTitle: 'customReportTitle',
reportPageTitle: 'customReportPageTitle',
takePassedScreenshot: true,
clearOldScreenshots: true,
shortScrFileNames: true,
jsonReport: false,
multiReport: false
},
timeout: 600000,
})
var file = ['./test/basic/app/']; //location of the test js
for (var i = 0; i < file.length; i++) {
fs.readdirSync(file[i]).forEach(function (filename) {
mocha.addFile(file[i] + filename);
});
}
mocha.run(function (failures) {
process.on('exit', function () {
process.exit(failures);
});
});
package.json
"scripts": {
"test": "mocha config.js"
},
Not sure about that, i think something was wrong in my configuration or else
The $ global is added through the WebdriverIO test runner. Since you're using wdio through standalone mode, you don't get access to those globals. Try this instead:
const elem = await client.$('#digit_2')
Make sure you're using the newest version of Webdriver.io. Webdriver.io v5 is the latest version that also implements the $('selector') shortcut.
If you're using Webdriver.io v4 - you may still need to use browser.element('selector') to find your elements.
It appears from the tags in your question, and the code you posted you maybe on version 4.
$ is usually used as a shorthand to run JQuery functions (such as your $('#digit_2'), in the "android_app_test.js" file).
From the WebdriverIO's doc:
The $ command is a short way to call the findElement command in order to fetch a single element on the page. It returns an object that with an extended prototype to call action commands without passing in a selector. However if you still pass in a selector it will look for that element first and call the action on that element.
To fix this you have to install JQuery with this commands:
In a terminal run:
npm install --save jquery
npm install --save-dev #types/jquery
then import it at the top of your "android_app_test.js" file like this
import * as $ from "jquery";
Related
I have made an extension that opens a file dialog. What I would like to do is after the file is selected, I want a python file to run. What I need is the VS Code command to run a file (or perhaps a python file specifically?).
here is a working example where the command I use is a command that comments the selected line in the currently active editor. It works perfectly so I know this structure is generally correct. I just need the right command to replace the comment line command.
below is the code in questions with the working command I mentioned above. I found it using this resource: where I found the comment line command
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const { ChildProcess } = require('child_process');
const vscode = require('vscode');
const { execFile } = require('node:child_process');
const { stdout, stderr } = require('process');
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
/**
* #param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand('fileDialog.openFile', function () {
const options = {
canSelectMany: false,
openLabel: 'Open'
};
vscode.window.showOpenDialog(options).then(fileUri => {
if (fileUri && fileUri[0]) {
console.log('Selected file: ' + fileUri[0].fsPath);
vscode.commands.executeCommand('python.execInInterminal');
}
});
});
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
function deactivate() {}
module.exports = {
activate,
deactivate
}
You can go for child_process' exec or spawn if you only need to run the Python script(s).
If you really prefer to rely on the Python extension, then you'll need to at least feed the script's Uri into the executeCommand's argument - its the 2nd part of what you found.
function activate(context) {
let disposable = vscode.commands.registerCommand('fileDialog.openFile', function () {
const options = {
canSelectMany: false,
openLabel: 'Open',
filters: {
'Python script': ['py']
}
};
vscode.window.showOpenDialog(options).then((fileUris) => {
// This will always get an array of Uris regardless of canSelectMany being false
fileUris?.forEach(async (fileUri) => {
console.log(`Selected file: ${fileUri.fsPath}`);
await vscode.commands.executeCommand('python.execInInterminal', fileUri);
});
});
});
context.subscriptions.push(disposable);
}
If you want to handle more things, you can refer to the thenable unittest code they included in the repo:
https://github.com/microsoft/vscode-python/blob/main/src/test/smoke/runInTerminal.smoke.test.ts#L46-L48
I am creating a test suite that will be run by mocha. In the test, I plan on using should and chai at the very least. I am testing JSON objects. I want mocha to be silent about successful tests and I want to control what the errors look like at the end of the run. Right now, there is a lot of red text describing the JSON object and other information. What I want is to override the output.
Here is an example test for an element in the JSON object which I would import from testData.
var should = require("should");
var chai = require("chai");
var expect = chai.expect;
const testData = require("./testData");
for (t of testData.data) {
describe("This will fail", function() {
it("Should have a zipperNut",function(done) {
t.should.have.property('zipperNut');
done();
});
});
}
What I want is to see just this:
$ mocha testSuite.js
zipperNut
$
And so on for all the tests I want to run. Can I do this? Do I need to use a different library?
Mocha's output is determined by something called a "default reporter". If you want to change the output you can specify a different reporter, which is presumably available through npm or similar. To specify a new custom reporter you do this:
$ mocha --reporter my-reporter.js
Where my-reporter.js is the file containing my "reporter". For me, I just want the plain name of the failing tests, so my reporter would look like:
'use strict';
const Mocha = require('mocha');
const {
EVENT_RUN_END,
EVENT_TEST_FAIL,
} = Mocha.Runner.constants;
class MyReporter {
constructor(runner) {
const stats = runner.stats;
runner
.on(EVENT_TEST_FAIL, (test, err) => {
console.log(
`${test.title}`
);
})
.once(EVENT_RUN_END, () => {
console.log(`end: ${stats.passes}/${stats.passes + stats.failures} ok`);
});
}
}
module.exports = MyReporter;
Documentation here:
https://mochajs.org/api/tutorial-custom-reporter.html
We are trying to use only nodeJS with minimal dependencies to other packages, the challenge we now encounter is HandelbarsJS. We found a package, Assemble who can generate html for us. Only, it is very very slow, about 3 seconds each time, of these 3 seconds, there are 2,5 / 2,7 seconds of the next line:
var assemble = require('assemble');
Our package.json script section:
"scripts": {
"build:handlebars": "node scripts/handlebars.js",
"watch:handlebars": "nodemon --watch assets --exec \"npm run build:handlebars\"" }
the script/handlebars.js file
#! /usr/bin/env node
var assemble = require('assemble');
var extname = require('gulp-extname');
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
Each time, when we save a .hbs file, Nodemon restart and the external javascript file will be called.
How can we ensure that 'require' get called only once, or whether they remain in memory?
Thank you!
Since you want to accomplish using this with assemble, but without gulp, I recommend chokidar.
npm install chokidar --save
Now you can require chokidar like this:
var chokidar = require('chokidar');
Then define a little helper that runs handler whenever something in a pattern changes:
function watch(patterns, handler) {
chokidar.watch(patterns, {
ignoreInitial: false
}).on('add', handler).on('change', handler).on('unlink', handler);
}
Now we can alter the script like this:
#! /usr/bin/env node
var assemble = require('assemble');
var extname = require('gulp-extname');
var chokidar = require('chokidar');
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
// Enable --watch command line for Chokidar, otherwise, just run!
if (process.argv.pop() === '--watch') {
watch('assets', runOnce);
} else {
runOnce();
}
function watch(patterns, handler) {
chokidar.watch(patterns, {
ignoreInitial: false
}).on('add', handler).on('change', handler).on('unlink', handler);
}
function runOnce() {
assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
}
And instead of nodemon, this will keep your script alive and running. So, in npm, you want this:
"scripts": {
"build:handlebars": "node scripts/handlebars.js",
"watch:handlebars": "node scripts/handlebars.js --watch"
}
Whenever a file changes, the script will now run, without re-invoking from scratch.
The beta version of assemble is based on gulp and has a cli that you can use just like you would use gulp, but if you don't want to use the cli and use npm scripts instead, you can do something based on #roel-van-uden's answer without chokidar and also be able to reload the actual assets (e.g. data, layouts, partials)
#! /usr/bin/env node
var start = Date.now();
var assemble = require('assemble');
var extname = require('gulp-extname');
assemble.task('assets', function () {
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
return assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
});
assemble.task('watch', ['assets'], function () {
assemble.watch('./assets/**/*.*', ['assets]');
});
// Enable --watch command line
if (process.argv.pop() === '--watch') {
assemble.run(['watch']);
} else {
assemble.run(['assets']);
}
I want to add an option for when debugging my generator or when working offline that will download npm and bower stuff from cache (by using --cache-min 999999 and --offline respectively).
Currently, this is my code (which both installs the dependencies and calls grunt bower):
CallumGenerator.prototype.installDeps = function () {
var cb = this.async();
this.installDependencies({
skipInstall: this.options['skip-install'],
callback: function () {
this.spawnCommand('grunt', ['bower'])
.on('close', function () {
cb();
});
}.bind(this)
});
};
It looks like I'll most likely have to call .npmInstall() and .bowerInstall() manually in order to specify options (I think?), but I don't know how to specify any options. To clarify, this is how I would do it in the console:
npm install --cache-min 999999 --save-dev grunt-contrib-less
bower install --offline --save jquery#1.10.2
You can't specify options directly from #installDependencies see: https://github.com/yeoman/generator/blob/master/lib/actions/install.js#L44-L69
You can specify them for both #npmInstall and bowerInstall https://github.com/yeoman/generator/blob/master/lib/actions/install.js#L121-L143
The options you pass are in the form of an object hash and will be parsed by dargs node modules, so you should follow the module conventions for declaring options
The code I used, which should be fine for anyone to use (you might want to get rid of the final callback, though):
CallumGenerator.prototype.installDeps = function () {
var cb = this.async();
this.npmInstall(null, {
skipInstall: this.options['skip-install'],
cacheMin: this.cachedDeps ? 999999 : 0
}, function () {
this.bowerInstall(null, {
skipInstall: this.options['skip-install'],
offline: this.cachedDeps
}, function () {
this.spawnCommand('grunt', ['bower'])
.on('close', function () {
cb();
});
}.bind(this));
}.bind(this));
};
It works fine. this.cachedDeps will define whether the cache is used or not.
Is it possible to user jasmine-node with the jQueryify feature of jsdom? What I'm trying to do is use NodeJS to test some JavaScript that depends on the presence of the DOM.
Here is a reduced case of what I tried. When I run the script, jasmine-node recognizes the spec, but doesn't run the expect():
var fs = require('fs'),
jsdom = require('jsdom'),
window = jsdom.createWindow(),
jasmine = require('jasmine-node')
describe("jQueryify", function() {
it('should run the test!', function () {
jsdom.jQueryify(window, function (window, jquery) {
expect(1).toEqual(1)
})
})
})
Alternately, is there a different/better way to test stuff in NodeJS that assumes a browser-like environment?
OK, based on one this answer to a semi-related question, I was able to get the expect() to execute. I guess the answer to my question is not to use the built-in jQueryify function, but to pull in jQuery 'manually'.
var fs = require('fs'),
window = require('jsdom').jsdom('<html><head></head><body></body></html>').createWindow(),
script = window.document.createElement('script'),
jasmine = require('jasmine-node')
describe("jQueryify", function() {
it('should run the test!', function () {
script.src = './path/to/jquery.js'
script.onload = function () {
expect(typeof window.$).toEqual('function')
asyncSpecDone()
}
window.document.head.appendChild(script)
asyncSpecWait()
})
})