{
let x = ref("x");
return {
onInit() {
this.addComputable("y", [x], (x: number) => x + 1);
},
};
}}
/>
,
);
let tree1 = component.toJSON();
assert.equal(store.get("y"), 1);
});
it("invokeParentMethod is invoked on parent instance", async () => {
let testValid: number[] = [];
class TestController1 extends Controller {
onInit() {
this.test();
}
test() {
testValid.push(1);
this.invokeParentMethod("test", 2);
}
}
class TestController2 extends Controller {
test(val: number) {
testValid.push(val);
}
}
let store = new Store();
const component = await createTestRenderer(
store,
,
);
// let tree = component.toJSON();
assert.deepStrictEqual(testValid, [1, 2]);
});
it("getParentControllerByType returns typed parent controller", async () => {
let parentValue = 0;
class ParentController extends Controller {
getValue() {
return 42;
}
}
class ChildController extends Controller {
onInit() {
let parent = this.getParentControllerByType(ParentController);
parentValue = parent.getValue();
}
}
let store = new Store();
const component = await createTestRenderer(
store,
,
);
assert.equal(parentValue, 42);
});
});
describe("Controller types", () => {
// Type-level tests - these verify that types work correctly at compile time
// If these compile, the types are working
interface MyControllerConfig extends ControllerConfig {
customValue?: number;
customMethod?(): void;
}
class MyController extends Controller {
declare customValue: number;
constructor(config?: MyControllerConfig) {
super(config);
}
customMethod() {
return this.customValue * 2;
}
}
it("accepts Controller class directly", async () => {
let store = new Store();
const component = await createTestRenderer(
store,
,
);
let tree = component.toJSON();
assert.ok(tree);
});
it("accepts config with type property", async () => {
let store = new Store();
let initCalled = false;
class TypedController extends Controller {
declare customValue: number;
constructor(config?: MyControllerConfig) {
super(config);
}
onInit() {
initCalled = true;
assert.equal(this.customValue, 42);
}
}
const component = await createTestRenderer(
store,
,
);
let tree = component.toJSON();
assert.ok(tree);
assert.equal(initCalled, true);
});
it("accepts inline config object with ThisType", async () => {
let store = new Store({ data: { count: 0 } });
const component = await createTestRenderer(
store,
,
);
let tree = component.toJSON();
assert.equal(store.get("count"), 1);
});
it("accepts factory function", async () => {
let store = new Store({ data: { count: 0 } });
const component = await createTestRenderer(
store,
({
onInit() {
set("count", 5);
},
})}
/>
,
);
let tree = component.toJSON();
assert.equal(store.get("count"), 5);
});
it("accepts CreateConfig with type and required properties", async () => {
let store = new Store({ data: { result: 0 } });
interface RequiredPropControllerConfig extends ControllerConfig {
multiplier: number; // Required property
}
class RequiredPropController extends Controller {
declare multiplier: number;
constructor(config?: RequiredPropControllerConfig) {
super(config);
}
onInit() {
this.store.set("result", 10 * this.multiplier);
}
}
const component = await createTestRenderer(
store,
,
);
assert.equal(store.get("result"), 50);
});
});