Anyone tried any page object pattern library to use with detox? Any suggestions or example on how to approach this? Thanks in advance.
I have, but in a closed source project. I now have a model like LoginPage.visit() or LoginPage.login() and I call them from the tests. What might be interesting is that I do the reset with device.reloadReactNative() in the tests. Otherwise you can do it exactly like in any other test lib with a pages folder you import from. Does this answer your question?
Thanks @DanielMSchmidt
So if I look at the example https://github.com/wix/detox/blob/master/examples/demo-native-ios/e2e/example.spec.js
And if I were to write a POM for this:
My spec file will be:
var loginPageObject = require('loginPage.js');
describe('Example', () => {
beforeEach(async () => {
await device.relaunchApp();
});
it('should have welcome screen', async () => {
await expect(loginPageObject.WelcomeButton).toBeVisible();
await expect(loginPageObject.HelloLabel).toBeVisible();
});
});
And PO file loginPage.js :
var welcomeButton = element(by.label('Welcome'));
var helloLabel = element(by.label('Say Hello'));
exports.WelcomeButton = welcomeButton;
exports.HelloLabel = helloLabel
So when I tried this, its giving me an error saying 'element' is not found. How does the same work in spec file as there is no reference to element or by.label etc.
Strange, element is exported when detox is initialized. Where does the po file live?
Exporting a function and passing element in could be a workaround
So my folder structure is:
-e2e
-pages
- loginPage.js
-specs
-loginSpec.js
-init.js
-mocha.opts
I don't get it, can you check your formatting maybe?
How about now, I updated my previous comment.
I think I was able to figure out. My export method was not correct. In my PO file:
var loginButton = 'Login';
var exports = module.exports = {};
exports.userLogin = function(){
return element(by.accessibilityLabel(loginButton));
}
And my spec file:
var loginObject = require('../pages/loginPage.js');
@kagalenitin
Did you reference the button by loginObject.loginButton? Trying to do the same but getting:
expect() argument is invalid, got undefined
when i am passing it to expect as await expect(loginObject.firstArticle).toBeVisible();
@aamorozov I think you need to export the variable, only then you can access it. I am doing that using function, not sure if its the correct way to do it.
@kagalenitin Yep that's exactly how i was doing that.. Not sure why it doesn't work though, is it passing for you?
It works for me.
Try if this works.
https://stackoverflow.com/questions/7612011/how-to-get-a-variable-from-a-file-to-another-file-in-node-js
@kagalenitin
I don't have issues with importing/exporting anything there(with both import/export or module.exports{}), but element command inside the page object doesn't work for me. Will be looking into this on the weekend so if anybody has any suggestions please advise
Nvm, got it working
What was the issue? @aamorozov - Good to have it documented for future reference. Thanks.
@kagalenitin So I ended up adding argument to function and passing there a var name for label:
export function tapOnNewElement(elem) {
return element(by.label(elem)).tap();
};
where elem is const defined and imported from selectors.js
My solution is something like:
class LoginScreen {
get emailInput() {
return element(by.id("text-input-email"));
}
get passwordInput() {
return element(by.id("text-input-password"));
}
get loginButton() {
return element(by.text("Login & view cleans"));
}
typeEmail(email) {
return this.emailInput.typeText(email);
}
typePassword(password) {
return this.passwordInput.typeText(password);
}
tapLoginButton() {
return this.loginButton.tap();
}
}
it("logs in a user", async() => {
const loginScreen = new LoginScreen();
await loginScreen.typeEmail('[email protected]');
await loginScreen.typePassword('password');
await loginScreen.tapLoginButton();
});
@lucassus , I tried your concept and got error as "ReferenceError: LoginScreen is not defined"
Any idea, what mistake I am doing?
detox test --configuration android.emu.debug
node_modules/.bin/jest e2e --config=e2e/config.json --maxWorkers=1 --testNamePattern='^((?!:ios:).)*$'
server listening on localhost:50167...
FAIL e2e/firstTest.spec.js (7.056s)
Example
✕ logs in a user (1272ms)
● Example › logs in a user
ReferenceError: LoginScreen is not defined
at Object._callee2$ (firstTest.spec.js:7:1)
at tryCatch (../node_modules/regenerator-runtime/runtime.js:62:40)
at Generator.invoke [as _invoke] (../node_modules/regenerator-runtime/runtime.js:296:22)
at Generator.prototype.(anonymous function) [as next] (../node_modules/regenerator-runtime/runtime.js:114:21)
at tryCatch (../node_modules/regenerator-runtime/runtime.js:62:40)
at invoke (../node_modules/regenerator-runtime/runtime.js:152:20)
at ../node_modules/regenerator-runtime/runtime.js:195:11
at new Promise (<anonymous>)
at callInvokeWithMethodAndArg (../node_modules/regenerator-runtime/runtime.js:194:16)
at AsyncIterator.enqueue [as _invoke] (../node_modules/regenerator-runtime/runtime.js:217:13)
at AsyncIterator.prototype.(anonymous function) [as next] (../node_modules/regenerator-runtime/runtime.js:114:21)
at Object.<anonymous>.runtime.async (../node_modules/regenerator-runtime/runtime.js:241:14)
at Object._callee2 (firstTest.spec.js:6:83)
at new Promise (<anonymous>)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 7.557s, estimated 8s
Ran all test suites matching /e2e/i with tests matching "^((?!:ios:).)*$".
child_process.js:643
throw err;
^
Error: Command failed: node_modules/.bin/jest e2e --config=e2e/config.json --maxWorkers=1 --testNamePattern='^((?!:ios:).)*$'
at checkExecSyncError (child_process.js:603:11)
at Object.execSync (child_process.js:640:13)
at runJest (/Users/neeraj.kumar/Neeraj/Projects/sampleApp/node_modules/detox/local-cli/detox-test.js:146:6)
at run (/Users/neeraj.kumar/Neeraj/Projects/sampleApp/node_modules/detox/local-cli/detox-test.js:81:7)
at Object.<anonymous> (/Users/neeraj.kumar/Neeraj/Projects/sampleApp/node_modules/detox/local-cli/detox-test.js:191:1)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
Just for the record, see my solution for above error. https://stackoverflow.com/questions/51356998/typeerror-loginscreen-visibleofwelcome-is-not-a-function