I am struggling to pass launch arguments to detox. For example if I want to pass a few different users as launch args. My init file looks like:
beforeAll(async () => {
await device.launchApp({
newInstance: true,
permissions: {notifications: 'YES'},
launchArgs: {
users: {
user1: { email: '123#abc.com', pass: '123456' },
user2: { email: 'abc#123.com', pass: '654321' },
}
}
});
});
However in my test file
await device.appLaunchArgs.get();
returns an empty object. Any ideas of what I am doing wrong? Am i misunderstanding what launchArgs are for?
The purpose of the launchArgs is to send parameters to the app being tested because you can't communicate with the app process otherwise. launchArgs enable you to configure specific app behavior, either (1) to pass dynamic parameters based on your test environment (e.g. ports of another process the app needs to connect to), or (2) to simulate a condition for a specific test case (e.g. you write two e2e tests, one that has some feature flag turned on and another one with it being off).
However in my test file
You don't access the values in a test file. Since the test file runs in the same node process as the beforeEach, there's no need to pass args. In fact, you can launch the app (with the appropriate args) directly in your test case, which is especially useful for the case (2) above.
To read the launchArgs in the app, you can create an .e2e.js mock file, and then use react-native-launch-arguments to retrieve the configured values. The rest is up to you but the general idea is to use the launch args in your app to change some part of business logic or configuration you want to test.
Related
In my application code, there are a lot of calls (like 100+) to the "top object" referring to window.top such as top.$("title") and so forth. Now, I've run into the problem using Cypress to perform end-to-end testing. When trying to log into the application, there are some calls to top.$(...) but the DevTools shows a Uncaught TypeError: top.$ is not a function. This resulted in my team and I discovering that the "top" our application is trying to reach is the Cypress environment itself.
The things I've tried before coming here are:
1) Trying to stub the window.top with the window object referencing our app. This resulted in us being told window.top is a read-only object.
2) Researching if Cypress has some kind of configuration that would smartly redirect calls to top in our code to be the top-most environment within our app. We figured we probably weren't the only ones coming across this issue.
If there were articles, I couldn't find any, so I came to ask if there was a way to do that, or if anyone would know of an alternate solution?
Another solution we considered: Looking into naming window objects so we can reference them by name instead of "window" or "top". If there isn't a way to do what I'm trying to do through Cypress, I think we're willing to do this as a last resort, but hopefully, we don't have to change that, since we're not sure how much of the app it will break upfront.
#Mikkel Not really sure what code I can provide to be useful, but here's the code that causes Cypress to throw the uncaught exception
if (sample_condition) {
top.$('title').text(...).find('content') // Our iframe
} else {
top.$('title').text(page_title)
}
And there are more instances in our code where we access the top object, but they are generally similar. We found out the root cause of the issue is that within Cypress calls to "top" actually interface with Cypress instead of their intended environment which is our app.
This may not be a direct answer to your question, it's just expanding on your request for more information about the technique that I used to pass info from one script to another. I tried to do it within the same script without success - basically because the async nature of .then() stopped it from working.
This snippet is where I read a couple of id's from sessionStorage, and save them to a json file.
//
// At this point the cart is set up, and in sessionStorage
// So we save the details to a fixtures file, which is read
// by another test script (e2e-purchase.js)
//
cy.window().then(window => {
const contents = {
memberId: window.sessionStorage.getItem('memberId'),
cartId: window.sessionStorage.getItem('mycart')
}
cy.writeFile(`tests/cypress/fixtures/cart.json`, contents)
})
In another script, it loads the file as a fixture (fixtures/cart.json) to pull in a couple of id's
cy.fixture(`cart`).then(cart => {
cy.visit(`/${cart.memberId}/${cart.cartId}`)
})
I'm trying to make logging easier for devs writing selenium tests with protractor.
I'm looking at selenium-webdriver/lib/logging and am trying to figure out how to make a convenient logging system.
Here is an example spec:
it('should NOT show welcome before login', () => {
// convenient log here
expect(homepage.logo.isPresent()).toBe(true);
// log message that would occur after expect
expect(homepage.welcomeText.isPresent()).toBe(false);
// final log message
});
I'm not quite sure how to go about this.
I'm trying to avoid having to do (below) for every log message.
homepage.welcomeText.isPresent().then(() => console.log('foo bar'));
There is a npm package - log4js-protractor-appender which will solve your problem.It is built specially for Protractor based environments and it places all logger command in Protractor Control flow and resolves Protractor promises before logging.
Since Protractor executes all commands in a Control Flow , and all non protractor commands dont get executed in the order we like. So regular logging will need an extra effort from us to chain a non-protractor command to a protractor command
Example:
browser.getCurrentUrl().then(function _logValue(url){
logger.info("The url is" + url);
});
But log4js-protractor-appender enabled to write something like this directly - browser.logger.info('Displayed text is:', browser.getCurrentUrl());
For more details on how to implement this- Please check my blog post - How to implements logs for Protractor/JavaScript based Test Automation Frameworks
For expects you can use toBeTruthy or Falsy and include message there. It would log if something goes wrong. Page Object pattern says you must not have weddriver methods in spec files meaning you may cretae method which would verify something present or not and then() log there like in your example. Also you can implement asyncLog function. console.log() method goes to Stack and executes before protractor methods since protractor's Control Flow or Managed Promise. It wraps every protractor method in deffered promise which puts it in callback queue which executes only after stack is empty. Take a look at next code. I didn't try it out for Protractor though but you can get the idea.
var promise = Promise.resolve();
function asyncLog(message) {
Promise.resolve().then(() => console.log(message));
}
console.log('Start');
promise
.then(() => console.log('This is then'))
asyncLog('This is Callback Queue log');
console.log('This is Call Stack log');
promise
.then(() => console.log('This is another then'))
In Intern framework, when I specify multiple tests using functionalSuites config field and run tests using BrowserStack tunnel, only one session is created in BrowserStack (everything is treated as a single test). As a result we have a few issues:
It's practically impossible to use BrowserStack for debugging for a large amount of tests. There is no navigation, you have to scroll over a huge log.
Tests are not fully isolated. For example, localStorage is shared between all tests.
The question: how to force Intern framework to create a new session for every single test? It seems like it's impossible at the moment after looking at the codebase.
PS: I would assume that this behaviour is applied to other tunnels as well.
Use the following Gist
intern-parallel.js
Just put this file alongside intern.js and replace "intern!object" in your functional test files with "tests/intern-parallel"
Example functional test
define([
//'intern!object',
'tests/intern-parallel',
'intern/chai!assert',
'require'
], function (registerSuite, assert, require, registry) {
registerSuite({
name: 'automate first test',
'google search': function () {
return this.remote
.get(require.toUrl('https://www.google.com'))
.findByName("q")
.type("Browserstack\n")
.end()
.sleep(5000)
.takeScreenshot();
}
});
});
Sorry for a newbie question, I am still new to mocha. I have an existing app that I am tasked to create a mocha test case. This app uses passport-auth0 and passport for user login. How do write mocha test such that I can login as a dummy user to test restricted functions?
Since Passport uses strategies that can be swapped in, one option is to put a mock in place of the actual auth0 strategy when running tests. That would look something like:
function MockStrategy() {
}
MockStrategy.prototype.authenticate = function(req) {
self.success({ id: 1, username: 'joe' );
}
// In test setup, mock out the strategy with one that returns
// dummy data.
passport.use('auth0', new MockStrategy());
Now you can write test cases where req.user will always be the joe as supplied by the mock strategy. You can extend that to cover authentication failures in a similar way.
That is my preferred approach, as it is least intrusive. Depending on how the application code is structured, there may be other dependencies that get required and need to be mocked out. For those situations, I've found proxyquire to be useful.
I am writing test for my custom DS.RESTAdapter, which uses our own SDK as transporter instead of ajax calls. Now, I want to test the adapters find, findAll, findQuery ... functions which require me to pass an instance of store as a parameter.
For example:
findAll: function(store, type, sinceToken){...}
To be able to test this, i need to pass "store" param which is not available in moduleFor in ember-qunit (unlike in moduleForModel where you can access store via this.store within the test instance).
Is there another way to gain access to the current instance of store?
Thanks.
Edit:
I solved this by creating mocks for both, store and type.
You can create a store instance by:
var store = DS.Store.create({
adapter: #subject
})
And a mock for type, just as an ordinary object with required properties for the test.
You can mock this method (for instance, using Sinon plugin for QUnit). Another solution for accessing the store (but I'm not sure it will work in your case) which helped me to access store from the global namespace is using setup and teardown methods:
setup: function () {
Ember.run(App, App.advanceReadiness);
},
teardown: function () {
App.reset();
}