Get help with testing, discuss unit testing strategies etc.


Post by KaguChan »

Hello there,

right now we're trying out siesta, which seems good so far.

But we're encountering one specific problem:
How to wait for preloads to complete?

The scenario is the following:
project.configure({
  title: 'Tests',
  preload: [
    {
      text: "console.log('preload started')",
    },
    'node_modules/sinon/pkg/sinon.js',
    'tests/api_stub.js',
    {
      text: "console.log('preload completed')",
    },
  ],
  loaderPath: { // i just tried it out while playing arround, but i guess for cmd i have to use another approach...
    'Ext.ux': 'node_modules/@sencha/ext-core/test/resources/ux',
  },
});

project.plan({
  group: '[Integration][Authorized][Mobile]',
  pageUrl: 'index.html?testing&phone',
  preload: 'inherit',
  alsoPreload: ['tests/hooks/loggedOut.js'], // for test purposes - actually we want the user to be logged in here
  items: [
    {
      title: 'Test Mobile capabilities',
      url: 'tests/integration/authorized/mobile/mobile.spec.js',
    },
  ],
});
  launch() {
    // Run test hooks if registered - hooks will run only when in debug mode
    // and when ?testing is given in application url
    TestHook.run();

    Log.trace(['Application', 'launch'], 'Launching application...');

    const mode = Ext.isMobileBrowser ? 'mobile' : 'desktop';
    Log.trace(['Application', 'launch'], `Loading application in ${mode} mode...`, Ext.tags);

    this.isLoggedIn = User.isLoggedIn();
    Log.trace(['Application', 'launch'], `User is logged ${this.isLoggedIn ? 'in' : 'out'}`);

    if (this.isLoggedIn) {
      return this.initWs(WS_URL, this.initState); // initialize a websocket connection, then the state manager
    }
    return this.showMain();
  },
Checking the console, we can see that the preload starts when the "initializing" text vanishes, but finnishes when extjs already did everything it needs - which is too late in this case.
  • The api stub is registered too late, so we cant fetch requests to /state on our server and fake them via sinon
  • The alsoPreload: loggedOut is registered too late, so we cannot stub the login check:
sinon.stub(User, 'isLoggedIn').returns(false);
We even tried to inject hooks, but the hooks, which are loaded via the preload, are injected way too late as well.

Is there a clean way to do stuff like this?
Ive also read this blog post: https://www.bryntum.com/blog/mocking-ajax-calls-with-siesta/ which is good for testing stuff after initialization, but some stuff requiring the api happens right within the initialization - how to mock these calls properly?

best regards
Kai Böse

=> log / load order / whatever:
preload started
Util.js?_dc=1562670758808:1135 [W] An existing reference is being overwritten for Test Mobile capabilities.app. See the appProperty config.
Log.js?_dc=1562670758808:21 [ Application init ] Initialising application...
Log.js?_dc=1562670758808:21 [ TESTING run ] run test hooks
Log.js?_dc=1562670758808:21 [ Application launch ] Launching application...
Log.js?_dc=1562670758808:21 [ Application launch ] Loading application in mobile mode...
Log.js?_dc=1562670758808:21 [ Application launch ] User is logged in
Log.js?_dc=1562670758808:21 [ Application initWs ] Initialising Websocket...
Log.js?_dc=1562670758808:21 [ Application onUnmatchedRoute ] Redirect to undefined
Log.js?_dc=1562670758808:21 [ Application initState ] Initialising state manager...
Log.js?_dc=1562670758808:21 [ Application showMain ] Loading app entry xtype: main
Log.js?_dc=1562670758808:21 [ MainController onBeforeRender ] Render process started - applying default listeners and data
Log.js?_dc=1562670758808:21 [ MainController onBeforeRender ] Navigation ready event fired
Log.js?_dc=1562670758808:21 [ Application showMain ] Register mobile view viewModel definition
Log.js?_dc=1562670758808:21 [ MainController onMainRouteUpdate ] kundensuche - undefined
Log.js?_dc=1562670758808:21 [ MainController checkAndRunRoute ] kundensuche - undefined; force: no
Log.js?_dc=1562670758808:21 [ MainController doMainRouteUpdate ] customerSearch attempted to be displayed...
api_stub.js:28 LULULULULULULU
VM51342:1 preload completed
loggedOut.js:5 LÖLÖLÖLÖLÖLÖLÖLÖLÖÖLÖLÖ

Post by nickolay »

Hi,

Not quite clear what you are trying to achieve, am I correct that you are trying to inject some mocking code during the application load?

When using `pageUrl` you can do that after the page has completely loaded (the regular `preload` option works like that). If that is too late, the best way probably will be to add some hook into the application itself, by analyzing the page url (as described in "Tesing Cmd App" guide).

Post by KaguChan »

This is exactly what im trying right now:
Ext.define('App.util.TestHook', {
  alternateClassName: ['TestHook'],
  singleton: true,

  hooks: [],

  register(fn) {
    this.hooks.push(fn);
  },

  run() {
    // <debug>
    if (Ext.isTesting) {
      Log.trace(['TESTING', 'run'], 'run test hooks', this.hooks);
      this.hooks.forEach((fn) => {
        Log.trace(['TESTING', 'HOOK'], 'run hook', fn);
        fn();
      });
    }
    // </debug>
  },
});
loggedOut.js:
TestHook.register(() => {
  console.log('LALALALALALALALA');
  sinon.stub(User, 'isLoggedIn').returns(false);
});
console.log('LÖLÖLÖLÖLÖLÖLÖLÖLÖÖLÖLÖ');
  launch() {
    // Run test hooks if registered - hooks will run only when in debug mode
    // and when ?testing is given in application url
    TestHook.run();

    Log.trace(['Application', 'launch'], 'Launching application...');

    const mode = Ext.isMobileBrowser ? 'mobile' : 'desktop';
    Log.trace(['Application', 'launch'], `Loading application in ${mode} mode...`, Ext.tags);

    this.isLoggedIn = User.isLoggedIn();
    Log.trace(['Application', 'launch'], `User is logged ${this.isLoggedIn ? 'in' : 'out'}`);

    if (this.isLoggedIn) {
      return this.initWs(WS_URL, this.initState);
    }
    return this.showMain();
  },
project.plan({
  group: '[Integration][Authorized][Mobile]',
  // waitForAppReady: true,
  pageUrl: 'index.html?testing&phone', // run the page with `testing`
  preload: 'inherit',
  alsoPreload: ['tests/hooks/loggedOut.js'], // load the hook itself
  items: [
    {
      title: 'Test Mobile capabilities',
      url: 'tests/integration/authorized/mobile/mobile.spec.js',
    },
  ],
});
As you can see on the original post, the regarding console log fires after the application has been initialized - leeding the hook just beeing registered too late.

I know about the `waitForExtReady` and the `waitForAppReady` configuration, but both of them does not seem to change the subject in this case.

Basically what we need is to have to preload files to be loaded before the Ext.application.init is called (or between init and launch).

I will try out avoiding the launch function doing anything if in testing and calling it manually for testing purposes, but before i tried i dont know if this works well...

EDIT
doing nothing works... ideas always comes after asking some other people...
  launch() {
    if (!Ext.isTesting) {
      this.runPage();
    }
    // In case we're testing, the app will be started manually
  },

  runPage() {
    this.started = true;
    // Run test hooks if registered - hooks will run only when in debug mode
    // and when ?testing is given in application url
    TestHook.run();

    Log.trace(['Application', 'launch'], 'Launching application...');

    const mode = Ext.isMobileBrowser ? 'mobile' : 'desktop';
    Log.trace(['Application', 'launch'], `Loading application in ${mode} mode...`, Ext.tags);

    this.isLoggedIn = User.isLoggedIn();
    Log.trace(['Application', 'launch'], `User is logged ${this.isLoggedIn ? 'in' : 'out'}`);

    if (this.isLoggedIn) {
      return this.initWs(WS_URL, this.initState);
    }
    return this.showMain();
  },
  
In the test:
  d.chain(
    (next) => {
      Ext.getApplication().runPage();
      next();
    },
    // ...

Post Reply