Testing editor class in node env

Throwing the towel and asking for help been trying to setup some tests for one of my classes as a proof of concept. but can seem to get over the initialization step.
Context
Want to add some CI to my project without having to ditch the editor. So i use the api rest tools to download the project. then with mocha i init pc globally and create and app using placanvas mock. then in test file:

import "../public/bsm_build/files/assets/189372713/1/entityRotation.js";
describe("EntityRotation", () => {
  it("should initialize with serverCalculated = false", () => {
    const entity = new pc.Entity();
    app.root.addChild(entity);
    entity.addComponent("script");
    // console.log("##### Scripts #######");
    // console.log(app.scripts.list());
    //
    // // Create script instance
    // const scriptInstance = entity.script.create("entityRotation");
    // console.log(scriptInstance); // Use this to
    //
    // // Assert that serverCalculated is false (default)
    // expect(scriptInstance.serverCalculated).to.be.false;
    //
    // // Initialize the script
    // scriptInstance.initialize();
    //
    // expect(scriptInstance.tumble).to.be.at.least(-200);
    // expect(scriptInstance.tumble).to.be.at.most(200);
    const scriptType = app.scripts.get("entityRotation");
    const instance = new scriptType({
      app: app,
      entity: entity,
      enabled: true,
    });
    instance.initialize();
    console.log("### Instance");
    console.log(Object.getOwnPropertyNames(scriptType.prototype));
    expect(instance.serverCalculated()).to.be.false;
  });

  it("should initialize with serverCalculated = true", () => {
    const entity = new pc.Entity();
    app.root.addChild(entity);
    entity.addComponent("script");
    const scriptInstance = entity.script.create("entityRotation", {
      attributes: { serverCalculated: true },
    });
    // scriptInstance.serverCalculated = true;
    console.log("### Script Instance");
    console.log(scriptInstance);
    scriptInstance.initialize();

    expect(scriptInstance.tumble).to.be.undefined;
  });
});

the class being tested

class EntityRotation extends pc.ScriptType {
  static addAttributes() {
    this.attributes.add("serverCalculated", {
      type: "boolean",
      default: false,
    });
  }
  initialize() {
    if (!this.serverCalculated) {
      this.tumble = Math.random() * 400.0 - 200.0;
    }
  }

  setTumble(tumble) {
    this.tumble = tumble;
  }

  update(dt) {
    if (!this.serverCalculated) {
      this.entity.rotateLocal(0, 0, this.tumble * dt);
    } else {
      this.entity.setEulerAngles(0, 0, this.tumble);
    }
  }
}

pc.registerScript(EntityRotation, "entityRotation");

EntityRotation.addAttributes();

can’t seem to be able to get attributes to populate, get a undefined error when accessing serverCalculated no matter what i do. The script is correctly registered in the app and the attribute is there if i do EntityRotation.attributes.get(‘serverCalculated’). Any and all help is greatly appreciated.

expect(instance.serverCalculated()).to.be.false

Not sure if related but serverCalculated is a property, not a function. So this should be

expect(instance.serverCalculated).to.be.false

Hey yaustar, thanks for reply. thats how i originally had it, added the method call () out of desperation after doing a inspection of instance. Sadly neither of them worked. O i also tried passing the attributes as args to new, but no luck maybe I have the wrong schema for attrs args. i’ll add the trace for more info.

SideNote: In editor there is deprecation notice to not extend from pc.ScriptType. But extending from pc.Script doesn’t quite work. wondering what should be the drop in replacement here?

Side SideNote: If i could use export statement in the editor it would have made setting up tests so much easier.

Trace

1) EntityRotation
       should initialize with serverCalculated = false:
     TypeError: Cannot read properties of undefined (reading 'serverCalculated')
      at EntityRotation.get (file://playcanvas_server/node_modules/playc
anvas/build/playcanvas/src/framework/script/script-attributes.js:166:29)
      at EntityRotation.initialize (file:///playcanvas_server/public/bsm_
build/files/assets/189372713/1/entityRotation.js:9:15)
      at Context.<anonymous> (file://playcanvas_server/pc_tests/entityRo
tation.test.js:29:14)
      at process.processImmediate (node:internal/timers:483:21)

  2) EntityRotation
       should initialize with serverCalculated = true:
     TypeError: Cannot read properties of undefined (reading 'serverCalculated')
      at EntityRotation.get (file:///playcanvas_server/node_modules/playc
anvas/build/playcanvas/src/framework/script/script-attributes.js:166:29)
      at EntityRotation.initialize (file://playcanvas_server/public/bsm_
build/files/assets/189372713/1/entityRotation.js:9:15)
      at ScriptComponent._scriptMethod (file:///playcanvas_server/node_mo
dules/playcanvas/build/playcanvas/src/framework/components/script/component.js:180:17)
      at ScriptComponent.create (file://playcanvas_server/node_modules/p
laycanvas/build/playcanvas/src/framework/components/script/component.js:354:13)
      at Context.<anonymous> (file://playcanvas_server/pc_tests/entityRo
tation.test.js:39:42)
      at process.processImmediate (node:internal/timers:483:21)

The source of my pain seems to always start in scrip-attributes.js no matter my changes. It like _attributes is always undefined.

I don’t suppose it’s possible to create a code pen on this or similar that I could debug?

I created this repo GitHub - jurgen-bsm/pc_test_repro: helper repo to help debug testing issues, its missing the rust server and the full game build download but running the test outputs same errors so should do the trick hopefully.

npm run test

There are two main issues.

  1. You were using PlayCanvas 2.0.0 which is a major breaking change version and has updated Script Type system and is why you were getting the errors about undefined attributes. The Editor is on 1.73.4. See Engine 2.0.0 (Root ticket) · Issue #6666 · playcanvas/engine · GitHub for more details. TLDR for now, you should be using PlayCanvas v1.

  2. When you create a script type on a script component, if it’s set to be enabled, it will call initialize immediately.

This is what the updated tests look like:

import "../public/build/entityRotation.js";
describe("EntityRotation", () => {
  it("should initialize with serverCalculated = false", () => {
    const entity = new pc.Entity();
    app.root.addChild(entity);
    entity.addComponent("script");
    const scriptInstance = entity.script.create("entityRotation", {
      enabled: false,
      attributes: { serverCalculated: false },
    });

    console.log("### Instance");
    console.log(Object.keys(scriptInstance));
    expect(scriptInstance.serverCalculated).to.be.false;
  });

  it("should initialize with serverCalculated = true", () => {
    const entity = new pc.Entity();
    app.root.addChild(entity);
    entity.addComponent("script");
    const scriptInstance = entity.script.create("entityRotation", {
      attributes: { serverCalculated: true }
    });
    expect(scriptInstance.tumble).to.be.undefined;
  });
});
2 Likes

On a separate note, the PlayCanvas team are working on getting ES6 module support in the Editor which will help with this. They are currently in alpha testing with this in the Editor and Engine v2

I can’t find the Editor ticket but you can see discussions about attributes here [RFC] JSDoc Script Attributes · Issue #1148 · playcanvas/editor · GitHub

Ah, here’s the project view ESM Scripts · GitHub

2 Likes