Detox: Page Object Pattern Suggestion

Created on 29 Jun 2017  ·  18Comments  ·  Source: wix/Detox

Anyone tried any page object pattern library to use with detox? Any suggestions or example on how to approach this? Thanks in advance.

questiostack overflow

All 18 comments

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?

@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)

Was this page helpful?
0 / 5 - 0 ratings