Not managing to chain selectors with $ and $$ as documented in Webdriver-IO docs - webdriver-io

I'm using Spectron's WebdriverIO which is at version 4.7.1 in node_modules. I'm trying to getText from an element but selecting it gradually is giving me trouble.
I can "Copy -> selector" in dev tools to give me a very specific path. This works if I .element(longPath).
What isn't working for me is chaining with $ and $$ (or element / elements):
const name = await client
.$($sideNav)
.$$($storageItem)[0]
.$('.StorageItem__header-info___browser-main-SideNav- span')
.getText()
Accessing [0] gives me undefined. If I log out the resolved value of $$($storageItem), I get:
[ { ELEMENT: '0.16994195059314898-2',
value: { ELEMENT: '0.16994195059314898-2' },
selector: '.StorageItem__root___browser-main-SideNav-',
index: 0 } ]
Any ideas why I can't chain as shown in the example here: http://webdriver.io/v4.7/api/utility/$.html
Many thanks.

Related

How to configure Create-react-app less module with customize-cra(2.x)?

I used create-react-app(typescripts) to build a project, and added antd#3.26.13 with customize-cra as the website I was following told me.
I would like use the module.css, and I want to use module.less, like css, but encountered some error messages:
./src/layout/basic.module.less (./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-8-1!./node_modules/postcss-loader/src??postcss!./node_modules/less-loader/dist/cjs.js??ref--6-oneOf-8-3!./src/layout/basic.module.less)
ValidationError: Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
- options has an unknown property 'localIdentName'. These properties are valid:
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }
My code follows:
const {
override,
addWebpackAlias,
fixBabelImports,
addLessLoader,
addDecoratorsLegacy
} = require('customize-cra');
module.exports = override(
addWebpackAlias({
"#":require('path').resolve(__dirname,"src")
}),
fixBabelImports('import',{
libraryName:'antd',
libraryDirectory:'es',
style:true
}),
addLessLoader({
javascriptEnabled:true,
modifyVars:{'#primary-color':'#1DA57A'},
}),
addDecoratorsLegacy()
);
The current version of customize-cra isn't compatible with the latest version of create-react-app, to be precise with css-loader. Try to install customize-cra#next to get alpha version. They fixed that issue there.

Cypress - run test in iframe

I'm trying to find elements in iframe but it doesn't work.
Is there anyone who have some system to run tests with Cypress in iframe? Some way to get in iframe and work in there.
It's a known issue mentioned here. You can create your own custom cypress command which mocks the iframe feature. Add following function to your cypress/support/commands.js
Cypress.Commands.add('iframe', { prevSubject: 'element' }, ($iframe, selector) => {
Cypress.log({
name: 'iframe',
consoleProps() {
return {
iframe: $iframe,
};
},
});
return new Cypress.Promise(resolve => {
resolve($iframe.contents().find(selector));
});
});
Then you can use it like this:
cy.get('#iframe-id')
.iframe('body #elementToFind')
.should('exist')
Also, because of CORS/same-origin policy reasons, you might have to set chromeWebSecurity to false in cypress.json (Setting chromeWebSecurity to false allows you to access cross-origin iframes that are embedded in your application and also navigate to any superdomain without cross-origin errors).
This is a workaround though, it worked for me locally but not during CI runs.
This works for me locally and via CI. Credit: Gleb Bahmutov iframes blog post
export const getIframeBody = (locator) => {
// get the iframe > document > body
// and retry until the body element is not empty
return cy
.get(locator)
.its('0.contentDocument.body').should('not.be.empty')
// wraps "body" DOM element to allow
// chaining more Cypress commands, like ".find(...)"
// https://on.cypress.io/wrap
.then(cy.wrap)
}
spec file:
let iframeStripe = 'iframe[name="stripe_checkout_app"]'
getIframeBody(iframeStripe).find('button[type="submit"] .Button-content > span').should('have.text', `Buy me`)
that is correct. Cypress doesn't support Iframes. It is simple not possible at the moment. You can follow (and upvote) this ticket: https://github.com/cypress-io/cypress/issues/136

Vue CLI 3 Nightwatch page object configuration

I'm using Vue CLI 3 version 3.0.5.
In project configuration, I use Nightwatch as e2e test tool.
I try to use page objects, so I had nightwatch.config.js file in project root, and add page_objects_path inside like below:
{
page_objects_path : "/tests/e2e/page-objects"
}
Then I create page-objects folder as this path: /tests/e2e/page-objects.
Then I setup a page object Entry.js under that folder and try to use it in test:
/tests/e2e/page-objects/Entry.js
vmodule.exports = {
'Test Page Object': browser => {
browser
.url(process.env.VUE_DEV_SERVER_URL)
.waitForElementVisible('#app', 5000)
browser.page.Entry().sayHello()
browser.end()
}
}
And the error message shows:
Cannot read property 'Entry' of undefined .
It looks like my page object setup is not correct...
Could anyone help providing a correct implementation of NightWatch page object in Vue CLI v3.0.5 ? Thanks...
Ah, I know why it won't work.
Because nightwatch.config.js is a javascript file, I should export it first, then the plugin can read it.
module.export = {
page_objects_path : "/tests/e2e/page-objects"
}
Sorry for the dumb question.

Trying with Nightwatch + Browserstack to set up a simple login test, failing

Using "nightwatch": "^1.0.11" and "browserstack-local": "^1.3.4"
I have tried this many ways, but I cannot get the examples in the documentation to run.
I have a simple login page with a page object
module.exports = {
url: function() {
return this.api.launchUrl + '/login';
},
elements: {
email: {
selector: '#user_login_email'
},
password: {
selector: '#user_login_password'
},
button: {
selector: '#login-btn'
}
}
};
I then want to run a test to login into the site (NOTE: The first screenshot is fine)
module.exports = {
before(client) {
client.maximizeWindow();
},
'Login' : function (client) {
var login = client.page.login();
login.navigate();
client.waitForElementPresent('body', 500)
.saveScreenshot('tests_output/login.png');
login.setValue('#email', 'test#user.email')
.setValue('#password', 'Pa55w0rd')
.click('#button');
client.pause(1000)
.saveScreenshot('tests_output/login-complete.png');
},
after(client) {
client.end();
}
};
I get the following errors when trying to run the test through browserstack (with the local URL)
✖ login.test
– Login (5.196s)
An error occurred while running .setValue() command on <Element [name=#email]>: Error: First argument passed to .elementIdValue() should be a web element ID string. Received object.
at Function.validateElementId (node_modules/nightwatch/lib/api/protocol.js:36:19)
at ProtocolActions.elementIdValue (node_modules/nightwatch/lib/api/protocol.js:951:25)
at transport.locateElement.then.result (node_modules/nightwatch/lib/api-loader/element-command.js:106:54)
at process._tickCallback (internal/process/next_tick.js:68:7)
at process._tickCallback (internal/process/next_tick.js:68:7)
at process._tickCallback (internal/process/next_tick.js:68:7)
An error occurred while running .setValue() command on <Element [name=#password]>: Error: First argument passed to .elementIdValue() should be a web element ID string. Received object.
[...]
An error occurred while running .click() command on <Element [name=#button]>: Error: First argument passed to .elementIdClick() should be a web element ID string. Received object.
[...]
I have gotten successful tests to run; just not using the documented examples.
For example, the below code works fine to close a cookie message
client
.waitForElementPresent('.cookie-message__button', 5, true, function(result) {
client.elementIdClick(result.value[0].ELEMENT);
})
.saveScreenshot('tests_output/cookie-closed.png');
But obviously it's really long winded.
Any help for what I'm doing wrong would be awesome.
Using the following as an example for the Nightwatch config: https://github.com/browserstack/nightwatch-browserstack/blob/master/conf/local.conf.js with the local runner and running tests in parallel in 3 browsers: https://github.com/browserstack/nightwatch-browserstack/blob/master/scripts/local.runner.js
TL;DR: Documentation examples don't work with version 1.0.11; but Nightwatch and Browserstack are configured correctly as can get a suite to run (in Travis and locally), just with very long-winded code, which I hacked together.
I have created sample project for page objects model here. Also, sample login test is added using page_objects_path.
The compatibility for latest nightwatch version is also added. The latest version of nightwatch seems to have changes which are in compliant with w3c. So we need to use 'browserName' as capability instead of 'browser'

Sencha Touch [APPNAME].app is undefined only when testing with Jasmine

I'm trying to set up some test cases for a view using the Jasmine 2.3.4 assertion library for my Sencha Touch 2.4 app. Things seem great (I see the view rendered to a div) except the browser does not know what MyApp.app is. I have this line at my onContainerInitialize function from my view/container code:
var controller = MyApp.app.getController('loginController');
which gives this Jasmine error:
TypeError: Cannot read property 'getController' of undefined
At the time the Jasmine tests are called, from my console I do have a MyApp global object with the following structure (attached). If you expand app you will see the class name of the controller listed in an array under _controllers. The line that causes this error in my spec file is:
var myView = new MyApp.view.someViewName({ renderTo: 'test' });
I modeled my setup after a few tutorials, one of which is Sencha's https://docs.sencha.com/extjs/4.2.5/#!/guide/testing
(wish there was one for a recent version of Touch). I think my problem may be related to this note midway down that page:
Note: this Application definition is not a copy and paste of your
regular Application definition in your app.js. This version will only
include the controllers, stores, models, etc and when launch is called
it will invoke the Jasmine tests.
It may be related, but I also couldn't follow their:
ctrl = newMyApp.controller.MyController();
where I would get this error:
TypeError: app.getRouter is not a function at Ext.define.applyRoutes (http://localhost:8080/touch/sencha-t...ug.js:45800:26)
Instead, I had to add in this argument like this:
var ctrl = new Kaacoo.controller.loginController({ application : app });
Additionally, my launch file is set up like this:
Ext.require('Ext.app.Application');
Ext.Loader.setConfig({
enabled: true,
disableCaching: true
});
Ext.Loader.setPath('MyApp', '../../app');
// this file is a couple levels deep from the root of my project
Ext.application({
name : 'MyApp',
extend: 'MyApp.Application',
autoCreateViewport: true,
controllers: [
'loginController'
],
requires : [
],
launch: function() {
// Jasmine is bootstrapped with boot.js referenced in the html runner, so nothing here. My test specs are being called after this launch function is executed.
}
});
The order I have listed my resources in my html runner are: Jasmine Library with boot.js> Touch All Debug Library > Project Source Files > Spec Files > Launch file
Building and simulating the app is fine, so why can't I also have access to MyApp.app.getController('loginController') as well in my test environment?
Thanks!