Skip to content

Commit 2ac237f

Browse files
committed
Setup and add first engine tests
1 parent 368fc06 commit 2ac237f

File tree

8 files changed

+219
-12
lines changed

8 files changed

+219
-12
lines changed

packages/engine/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ module.exports = {
1515
"^y-protocols/([a-zA-Z-]*)$":
1616
"<rootDir>/../../node_modules/y-protocols/dist/$1.cjs",
1717
},
18-
setupFiles: ["<rootDir>/src/setupTests.ts"],
18+
setupFiles: ["<rootDir>/src/tests/setupTests.ts"],
1919
};

packages/engine/src/my.test.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

packages/engine/src/setupTests.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { CodeModel } from "../CodeModel";
2+
import { Engine } from "../Engine";
3+
import { event } from "vscode-lib";
4+
import {
5+
buildMockedModel,
6+
importResolver,
7+
toUMDFormat,
8+
waitTillEvent,
9+
} from "./utils/helpers";
10+
11+
const getModel1 = () =>
12+
buildMockedModel(
13+
"model1",
14+
`let x = 4;
15+
let y = 6;
16+
let sum = x + y;
17+
exports.sum = sum;
18+
exports.default = sum;`
19+
);
20+
21+
const getModel2 = () =>
22+
buildMockedModel("model2", `exports.default = $.sum - 5;`);
23+
24+
describe("engine class", () => {
25+
it("should execute a single model", async () => {
26+
const engine = new Engine<CodeModel>(importResolver);
27+
engine.registerModel(getModel1());
28+
29+
const { model, output } = await event.Event.toPromise(engine.onOutput);
30+
31+
expect(model.path).toBe("model1");
32+
expect(output.sum).toBe(10);
33+
expect(output.default).toBe(10);
34+
});
35+
36+
it("should read exported variables from other models", async () => {
37+
const engine = new Engine<CodeModel>(importResolver);
38+
engine.registerModel(getModel1());
39+
await event.Event.toPromise(engine.onOutput);
40+
41+
engine.registerModel(getModel2());
42+
const { model, output } = await event.Event.toPromise(engine.onOutput);
43+
44+
expect(model.path).toBe("model2");
45+
expect(output.default).toBe(5);
46+
});
47+
48+
it("should re-evaluate code after change", async () => {
49+
const engine = new Engine<CodeModel>(importResolver);
50+
const model1 = getModel1();
51+
52+
engine.registerModel(model1);
53+
await event.Event.toPromise(engine.onOutput);
54+
55+
model1.updateCode(
56+
toUMDFormat(`let x = 0;
57+
let y = 6;
58+
let sum = x + y;
59+
exports.sum = sum;
60+
exports.default = sum;`)
61+
);
62+
63+
const { output } = await event.Event.toPromise(engine.onOutput);
64+
65+
expect(output.sum).toBe(6);
66+
expect(output.default).toBe(6);
67+
});
68+
69+
it("should re-evaluate other models when global variable changes", async () => {
70+
const engine = new Engine<CodeModel>(importResolver);
71+
const eventsPromise = waitTillEvent(engine.onOutput, 5);
72+
const model1 = getModel1();
73+
const model2 = getModel2();
74+
75+
engine.registerModel(model1);
76+
engine.registerModel(model2);
77+
78+
model1.updateCode(
79+
toUMDFormat(`let x = 0;
80+
let y = 6;
81+
let sum = x + y;
82+
exports.sum = sum;
83+
exports.default = sum;`)
84+
);
85+
86+
const events = await eventsPromise;
87+
const eventsSnapshot = events.map((event) => ({
88+
path: event.model.path,
89+
output: event.output,
90+
}));
91+
const finalEvent = eventsSnapshot[eventsSnapshot.length - 1];
92+
93+
expect(finalEvent.path).toBe("model2");
94+
expect(finalEvent.output.default).toBe(1);
95+
expect(eventsSnapshot).toMatchSnapshot();
96+
});
97+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`engine class should re-evaluate other models when global variable changes 1`] = `
4+
Array [
5+
Object {
6+
"output": Object {
7+
"default": 10,
8+
},
9+
"path": "model1",
10+
},
11+
Object {
12+
"output": Object {
13+
"default": 5,
14+
},
15+
"path": "model2",
16+
},
17+
Object {
18+
"output": Object {
19+
"default": 5,
20+
},
21+
"path": "model2",
22+
},
23+
Object {
24+
"output": Object {
25+
"default": 6,
26+
},
27+
"path": "model1",
28+
},
29+
Object {
30+
"output": Object {
31+
"default": 1,
32+
},
33+
"path": "model2",
34+
},
35+
]
36+
`;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// jest-dom adds custom jest matchers for asserting on DOM nodes.
2+
// allows you to do things like:
3+
// expect(element).toHaveTextContent(/react/i)
4+
// learn more: https://github.com/testing-library/jest-dom
5+
// import "@testing-library/jest-dom";
6+
// https://github.com/developit/microbundle/issues/708, otherwise vscode-lib fails
7+
import "regenerator-runtime/runtime.js";
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { CodeModel } from "../../CodeModel";
2+
import { event } from "vscode-lib";
3+
4+
export class CodeModelMock implements CodeModel {
5+
public contentChangeEmitter = new event.Emitter<void>();
6+
7+
public onWillDispose() {
8+
return {
9+
dispose: () => {},
10+
};
11+
}
12+
public onDidChangeContent = this.contentChangeEmitter.event;
13+
14+
constructor(
15+
public readonly language: string,
16+
public readonly path: string,
17+
public code: string
18+
) {}
19+
20+
public getValue(): string {
21+
return this.code;
22+
}
23+
24+
public updateCode(code: string) {
25+
this.code = code;
26+
this.contentChangeEmitter.fire();
27+
}
28+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { CodeModel } from "../../CodeModel";
2+
import { ResolvedImport } from "../../Engine";
3+
import { CodeModelMock } from "./CodeModelMock";
4+
5+
export function waitTillEvent<T>(
6+
e: (listener: (arg0: T) => void) => void,
7+
expected: number
8+
): Promise<T[]> {
9+
const captured: T[] = [];
10+
return new Promise((resolve) => {
11+
e(({ ...args }) => {
12+
if (captured.length < expected) {
13+
captured.push(args);
14+
}
15+
if (captured.length === expected) {
16+
return resolve(captured);
17+
}
18+
});
19+
});
20+
}
21+
22+
export async function importResolver(
23+
_module: string,
24+
_forModel: CodeModel
25+
): Promise<ResolvedImport> {
26+
const res = async () => {
27+
return {
28+
module: {
29+
default: {},
30+
},
31+
dispose: () => {},
32+
};
33+
};
34+
35+
return res();
36+
}
37+
38+
export function toUMDFormat(code: string) {
39+
return `define(["require", "exports"], function(require, exports) {
40+
"use strict";
41+
Object.defineProperty(exports, "__esModule", { value: true });
42+
${code}
43+
});
44+
`;
45+
}
46+
47+
export function buildMockedModel(name: string, code: string) {
48+
const umdFormat = toUMDFormat(code);
49+
return new CodeModelMock("javascript", name, umdFormat);
50+
}

0 commit comments

Comments
 (0)