Cannot test a native Android app using codeceptJS - appium-android

I have created a codeceptJS project by following the mobile testing setup steps located here: https://codecept.io/mobile/#setting-up
So far, I'm unable to test any apps via simulator; I instead get the following error:
1) login
I should be able to login with the correct username and password:
>> The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource <<
at Object.getErrorFromResponseBody (node_modules/webdriver/build/utils.js:189:12)
at NodeJSRequest._request (node_modules/webdriver/build/request/index.js:157:31)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
I have verified my appium config using appium-doctor, and there are no issues found.
My codecept.conf.js is as follows:
const path = require('path');
const { setHeadlessWhen } = require('#codeceptjs/configure');
// turn on headless mode when running with HEADLESS=true environment variable
// export HEADLESS=true && npx codeceptjs run
setHeadlessWhen(process.env.HEADLESS);
exports.config = {
tests: './*_test.js',
output: './output',
helpers: {
Appium: {
platform: 'Android',
device: 'emulator',
desiredCapabilities: {
avd: 'Pixel_5_API_28',
app: path.resolve('./sample_apps/Android.apk'),
appActivity: 'com.swaglabsmobileapp.MainActivity'
}
},
},
include: {
I: './steps_file.js'
},
bootstrap: null,
mocha: {},
name: 'appium-codecept-android-POC',
plugins: {
pauseOnFail: {},
retryFailedStep: {
enabled: true
},
tryTo: {
enabled: true
},
screenshotOnFail: {
enabled: true
}
}
}
And here's my package.json as created by codeceptjs init:
{
"name": "appium-codecept-android-POC",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"codeceptjs": "^3.0.7",
"webdriverio": "^7.9.0"
}
}
Finally, my test file is as follows:
Feature('login');
Scenario('I should be able to login with the correct username and password', ({ I }) => {
setTimeout(() => {
I.see('Username');
}, 3000);
I.click('//android.widget.EditText[#content-desc="test-Username"]');
I.fillField('//android.widget.EditText[#content-desc="test-Username"]', 'standard_user');
I.click('//android.widget.EditText[#content-desc="test-Password"]');
I.fillField('//android.widget.EditText[#content-desc="test-Password"]', 'secret_sauce');
I.click('//android.view.ViewGroup[#content-desc="test-LOGIN"]');
I.waitForElement('//android.view.ViewGroup[#content-desc="test-Cart drop zone"]/android.view.ViewGroup/android.widget.TextView', 3)
I.dontSeeElement('//android.view.ViewGroup[#content-desc="test-Error message"]/android.widget.TextView');
});
Scenario('I should not be able to login with an incorrect username or password', ({ I }) => {
setTimeout(() => {
I.see('Username');
}, 3000);
I.click('//android.widget.EditText[#content-desc="test-Username"]');
I.fillField('//android.widget.EditText[#content-desc="test-Username"]', 'bob');
I.click('//android.widget.EditText[#content-desc="test-Password"]');
I.fillField('//android.widget.EditText[#content-desc="test-Password"]', 'secret_sauce');
I.click('//android.view.ViewGroup[#content-desc="test-LOGIN"]');
I.waitForElement('//android.view.ViewGroup[#content-desc="test-Cart drop zone"]/android.view.ViewGroup/android.widget.TextView', 3)
I.dontSeeElement('//android.view.ViewGroup[#content-desc="test-Error message"]/android.widget.TextView');
});
Scenario('I should be able to see details', ({ I }) => {
// login
setTimeout(() => {
I.see('Username');
}, 3000);
I.click('//android.widget.EditText[#content-desc="test-Username"]');
I.fillField('//android.widget.EditText[#content-desc="test-Username"]', 'standard_user');
I.click('//android.widget.EditText[#content-desc="test-Password"]');
I.fillField('//android.widget.EditText[#content-desc="test-Password"]', 'secret_sauce');
I.click('//android.view.ViewGroup[#content-desc="test-LOGIN"]');
I.waitForElement('//android.view.ViewGroup[#content-desc="test-Cart drop zone"]/android.view.ViewGroup/android.widget.TextView', 3)
// should be able to click a label to see details
I.click('(//android.widget.TextView[#content-desc="test-Item title"])[2]');
I.seeElement('//android.view.ViewGroup[#content-desc="test-Description"]/android.widget.TextView[2]');
I.click('//android.view.ViewGroup[#content-desc="test-BACK TO PRODUCTS"]');
});
I'm at a loss here, as I haven't done anything except follow the setup instructions. Executing against ios works; it is only the android execution that fails. Appium is installed and running, env vars are set, etc. Any help would be appreciated, as this could be a deal breaker for me in terms of whether or not I can use codeceptjs. I love the project and really want to use it, but I must be able to test both ios and android native apps.
One final note: If anyone wants to try this config, the app I am using for the above test can be found here: https://github.com/saucelabs/sample-app-mobile/releases/download/2.7.1/Android.SauceLabs.Mobile.Sample.app.2.7.1.apk

Related

MERN-Stack Heroku - Cannot GET /

Trying to get a MERN-Stack to Deploy on Heroku I've added MONGOBD_URI as a key in Config Vars on Heroku and added the MongoDB Atlas value.
Heroku is connected directly to the Github repo and not through the Heroku CLI. I have it set to auto-deploy but recently redeployed it manually.
This was the Heroku Build Log:
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_VERBOSE=false
NODE_ENV=production
NODE_MODULES_CACHE=true
-----> Installing binaries
engines.node (package.json): unspecified
engines.npm (package.json): unspecified (use default)
Resolving node version 12.x...
Downloading and installing node 12.20.0...
Using default npm version: 6.14.8
-----> Restoring cache
Cached directories were not restored due to a change in version of node, npm, yarn or stack
Module installation may take longer for this build
-----> Installing dependencies
Installing node modules
> nodemon#2.0.6 postinstall /tmp/build_b41198ca_/node_modules/nodemon
> node bin/postinstall || exit 0
Love nodemon? You can now support the project via the open collective:
> https://opencollective.com/nodemon/donate
added 290 packages in 6.983s
-----> Build
-----> Caching build
- node_modules
-----> Pruning devDependencies
removed 1 package and audited 289 packages in 2.051s
17 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
-----> Build succeeded!
-----> Discovering process types
Procfile declares types -> (none)
Default types for buildpack -> web
-----> Compressing...
Done: 33M
-----> Launching...
Released v17
https://jms-r0b.herokuapp.com/ deployed to Heroku
The browser(Chrome) only renders Cannot GET / and consol.log()'s GET https://jms-r0b.herokuapp.com/ 404 (Not Found) jms-r0b.herokuapp.com/:1
This is the LINK to my repo.
Here's how my server.js is setup:
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");
const todoRoutes = express.Router();
const PORT = process.env.PORT || 4000;
let Todo = require("./models/todo.model");
app.use(cors());
app.use(bodyParser.json());
// Express data parsing
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static("public"));
const URI = process.env.MONGODB_URI || "mongodb://localhost/todos";
mongoose.connect(
URI,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
},
(err) => console.log(err)
);
const connection = mongoose.connection;
connection.once("open", () => {
console.log("MongoDB database connection established successfully");
});
todoRoutes.route("/").get((req, res) => {
Todo.find((err, todos) => {
if (err) {
console.log(err);
} else {
res.json(todos);
}
});
});
todoRoutes.route("/:id").get((req, res) => {
let id = req.params.id;
Todo.findById(id, (err, todo) => {
res.json(todo);
});
});
todoRoutes.route("/update/:id").post((req, res) => {
Todo.findById(req.params.id, (err, todo) => {
if (!todo) {
res.status(404).send("data is not found");
} else {
todo.todo_description = req.body.todo_description;
todo.todo_responsible = req.body.todo_responsible;
todo.todo_priority = req.body.todo_priority;
todo.todo_completed = req.body.todo_completed;
todo
.save()
.then((todo) => {
res.json("Todo updated!");
})
.catch((err) => {
res.status(400).send("Update not possible");
});
}
});
});
todoRoutes.route("/add").post((req, res) => {
let todo = new Todo(req.body);
todo
.save()
.then((todo) => {
res.status(200).json({ todo: "todo added successfully" });
})
.catch((err) => {
res.status(400).send("adding new todo failed");
});
});
todoRoutes.route("/delete/:id").delete((req, res) => {
Todo.findByIdAndRemove(req.params.id, (err, todo) => {
if (!todo) {
res.status(404).send("data is not found");
} else {
res.status(200).json({
msg: todo,
});
}
});
});
app.use("/todos", todoRoutes);
app.listen(PORT, () => {
console.log("http://localhost:" + PORT);
console.log(".env.PORT:" + process.env.PORT);
});
and this is how my root package.json looks:
{
"name": "rob",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start:dev": "cd client && npm start",
"client": "cd client && npm run start",
"start": "concurrently \"node server/server.js\" \"npm run client\"",
"dev": "concurrently \"nodemon server/server.js\" \"npm run client\""
},
"repository": {
"type": "git",
"url": "git+https://github.com/WasteOfADrumBum/r0b.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/WasteOfADrumBum/r0b/issues"
},
"homepage": "https://github.com/WasteOfADrumBum/r0b#readme",
"dependencies": {
"bcryptjs": "^2.4.3",
"concurrently": "^5.3.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-mongo-sanitize": "^2.0.0",
"express-rate-limit": "^5.1.3",
"helmet": "^4.2.0",
"hpp": "^0.2.3",
"ini": "^2.0.0",
"mongoose": "^5.10.13",
"nodemon": "^2.0.6",
"react": "^17.0.1",
"react-cool-onclickoutside": "^1.5.8",
"react-dom": "^17.0.1",
"validator": "^12.0.0",
"xss-clean": "^0.1.1"
},
"devDependencies": {
"dotenv": "^8.2.0"
}
}
I could use a little help. I've deployed 5 other MERN-Stacks with a MongoDB Atlas or JawsDB connection with little to no issues and this one is just throwing me for a loop.
PLEASE HELP!!!
Everyone does things differently, but I think the error is in your connection to MongDB- are you establishing a connection OK or no?
If no connection - You said "I've added MONGOBD_URI as a key in Config Vars on Heroku and added the MongoDB Atlas value." But I see that "config Vars" is not used in your code- you used the .env as you should to keep your connection password secure...so may just need to add your connection URI to the .env file, and you are good to go?
If your connection is fine, then I would look to your server and suggest to test if the problem is solved using the standard routing:
app.route("/")
.get(function(req, res) {
res.sendFile(process.cwd() + "/views/index.html");
})

Set static path for karma runner

I was able prepare my OpenUI5 app for testing. I am having issue with the working directory for tests, because for my test I need to use a pre-populated sqlite3 database. For testing I use chrome with parameters --user-data-dir="C:\tmp" --profile-directory="karma", and I can place this file into chrome profile path. But I am not able to do this with karma, because karma always start with randomly generated id in path (karma-xxxxxx).
I am trying run custom browser config, with above chrome parameters, but it does not work.
module.exports = function(config) {
"use strict";
var chromeFlags = [
"--window-size=1280,1024",
"--disable-web-security",
"--allow-file-access-from-files",
'--user-data-dir="C:\\tmp"',
'--profile-directory="karma"'
];
config.set({
basePath: '',
ui5: {
type: "application",
preload: 'async',
animation: 'false',
paths: {
webapp: "www", // application
}
},
frameworks: ["ui5"],
browsers: ["CustomChrome"],
browserConsoleLogOptions: {
level: "error"
},
customLaunchers: {
CustomChrome: {
base: "Chrome",
flags: chromeFlags
},
CustomChromeHeadless: {
base: "ChromeHeadless",
flags: chromeFlags
}
},
});
};
with this config, chrome always start like this, so automatic testing does not work:

Gatsby trailing slash redirect issue only on deployed version

In my Gatsby app, I want the following routes:
/branches - shows stores' branch locations.
/branches/:id - shows information about a particular branch.
To accomplish this, I have the following folder structure:
src
pages
branches
index.tsx
Inside index.tsx, I have:
import React from 'react'
import { Router } from '#reach/router'
const Comp = (props: { path: any }) => {
return <pre>{JSON.stringify(props, null, 2)}</pre>
}
export default () => {
return (
<Router>
<Comp path="/branches" />
<Comp path="/branches/:id" />
</Router>
)
}
(The Comp component is there just to show the functionality is working.)
In my gatsby-node.js file, I have this:
// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// page.matchPath is a special key that's used for matching pages
// only on the client.
if (page.path.match(/^\/branches/)) {
page.matchPath = '/branches/*'
// Update the page.
createPage(page)
}
}
So the result is that when I am running gatsby develop, everything works as expected. I can visit /branches and /branches/4 and I see what I expect, the Comp component displaying some routing information:
{
"path": "/branches",
"uri": "/branches",
"location": {
"pathname": "/branches/",
"search": "",
"hash": "",
"href": "http://localhost:1337/branches/",
"origin": "http://localhost:1337",
"protocol": "http:",
"host": "localhost:1337",
"hostname": "localhost",
"port": "1337",
"state": null,
"key": "initial"
}
}
However, when running deploying to S3 using gatsby build && gatsby-plugin-s3 deploy --yes, I get into a redirect loop:
What is the issue here and how can I resolve it?
(I have experimented with the gatsby-plugin-force-trailing-slashes and gatsby-plugin-remove-trailing-slashes plugins to no avail)

Protractor W3C capability

I am using Protractor with Selenoid. I need to use the dockerized Windows images so that I can test Internet Explorer and Edge from Linux boxes.
I was able to make it work from curl by running:
curl -X POST http://127.0.0.1:4444/wd/hub/session -d '{"capabilities":{"browserName":"MicrosoftEdge","count":1,"alwaysMatch":{"browserName":"MicrosoftEdge","selenoid:options":{"enableVNC":true,"enableVideo":false,"enableLog":true,"logName":"edge-18.0.log"}}}}'
My protractor config looks like:
multiCapabilities: [
{
browserName: "MicrosoftEdge",
"alwaysMatch": {
browserName: "MicrosoftEdge",
"selenoid:options": {
enableVNC: true,
enableVideo: false,
enableLog: true,
logName: "edge-18.0.log"
}
}
}
]
But protractor send it over the selenoid server like this:
{
"desiredCapabilities": {
"browserName": "MicrosoftEdge",
"count": 1,
"alwaysMatch": {
"browserName": "MicrosoftEdge",
"selenoid:options": {
"enableVNC": true,
"enableVideo": false,
"enableLog": true,
"logName": "edge-18.0.log"
}
}
}
}
The issue is that desiredCapabilities should just be 'capabilities`. I have been looking everywhere trying to find out where is that created so that I can created some sort of flag to be able to switch it.
Any ideas?
Using Protractor 6.0 solve my issue, but broke all my tests.
I was able to keep using 5.4.1 by patching the selenium-webdriver package. Looking at the way Protractor 6 did it, I did it to Protractor 5.4.1:
I edited the file located at node_modules/selenium-webdriver/lib/webdriver.js and added the following:
// Capability names that are defined in the W3C spec.
const W3C_CAPABILITY_NAMES = new Set([
'acceptInsecureCerts',
'browserName',
'browserVersion',
'platformName',
'pageLoadStrategy',
'proxy',
'setWindowRect',
'timeouts',
'unhandledPromptBehavior',
]);
Then in the same file I modify the static createSession(executor, capabilities, opt_flow, opt_onQuit) method to add the following:
let W3CCaps = new Capabilities(capabilities);
for (let k of W3CCaps.keys()) {
// Any key containing a colon is a vendor-prefixed capability.
if (!(W3C_CAPABILITY_NAMES.has(k) || k.indexOf(':') >= 0)) {
W3CCaps.delete(k);
}
}
cmd.setParameter('capabilities', W3CCaps);
After all those changes the request getting to Selenoid is like this:
{
"desiredCapabilities": {
"browserName": "MicrosoftEdge",
"version": "18.0",
"enableVNC": true,
"enableVideo": false,
"count": 1
},
"capabilities": {
"browserName": "MicrosoftEdge"
}
}
And my Protractor 5 config looks like this:
multiCapabilities: [{
browserName: 'MicrosoftEdge',
version: '18.0',
enableVNC: true,
enableVideo: false
}]
Note:
So that I don't have to worry about refresh installs or updates I use the package patch-package (https://github.com/ds300/patch-package) to create a patch that is applied when any of those events happen. Here is a great video explaining how to use that package https://www.youtube.com/watch?v=zBPcVGr6XPk

electron-builder cannot find git repository although specifying

package.json
{
//some other config
"repository": "git#gitintsrv.domain.com/UserName/RepoName",
"scripts": {
"build": "build --win",
"ship": "build --win -p always"
}
}
electron-builder.yml
appId: com.xorchat.app.windows
publish:
provider: github
token: some_token
electron.js
const { app, BrowserWindow, ipcMain } = require('electron');
const { autoUpdater } = require("electron-updater");
let win; // this will store the window object
// creates the default window
function createDefaultWindow() {
win = new BrowserWindow({ width: 900, height: 680 });
win.loadURL(`file://${__dirname}/src/index.html`);
win.on('closed', () => app.quit());
return win;
}
// when the app is loaded create a BrowserWindow and check for updates
app.on('ready', function() {
createDefaultWindow()
autoUpdater.checkForUpdates();
});
// when the update has been downloaded and is ready to be installed, notify the BrowserWindow
autoUpdater.on('update-downloaded', (info) => {
win.webContents.send('updateReady')
});
// when receiving a quitAndInstall signal, quit and install the new version ;)
ipcMain.on("quitAndInstall", (event, arg) => {
autoUpdater.quitAndInstall();
})
When i am running npm run build i am receiving this error.
Error: Cannot detect repository by .git/config. Please specify "repository" in the package.json (https://docs.npmjs.com/files/package.json#repository).
Please see https://electron.build/configuration/publish
Where is the error?
I know it's probably too late, but in case you end up here as I did, here's how I solved it:
Add this to your package.json
"build": {
"publish": [{
"provider": "github",
"host": "github.<<DOMAIN>>.com",
"owner": "<<USER>>",
"repo": "<<NAME OF YOUR REPO (ONLY THE NAME)>>",
"token": "<<ACCESS TOKEN>>"
}]
}
I think the issue is that electron cannot parse corporate github urls, or something.
*********** EDIT:
Make a electron-builder.yml in the root folder, with the following content
appId: com.corporate.AppName
publish:
provider: github
token: <<ACCESS TOKEN>>
host: github.corporate.com
owner: <<User/ Org>>
repo: <<repo name>>
Don't forget to include this file on your .gitignore
This use to be a specific issue with Electron Builder 19x, and it has since been fixed:
https://github.com/electron-userland/electron-builder/issues/2785