Files
GDevelop/GDevelop.js/__tests__/GDJSLegacySceneVariableCodeGenerationIntegrationTests.js
Florian Rival a51c223c9c Add experimental, work-in-progress visual editor for custom objects (aka "prefabs"/"templates") (#6699)
* Still to do: 
  * Properly handle effects (disable 3D effects) for layers
  * Handle hot reloading properly
  * Avoid duplicating the configuration of the custom object inside each object created from it. Instead, only store the modified values.
  * Add a "Extract as a custom object ("prefab")" when selecting instances in a scene.
  * Add a dialog to give choice between 2D or 3D object when creating one.
  * Make sure "behavior shared data" are properly handled (physics, pathfinding...)
  * Check if we need to give an expression to translate coordinates from the parent to the local custom object.
  * Ensure a deleted custom object does not break the editor

Co-authored-by: Davy Hélard <davy.helard@gmail.com>
2024-07-11 11:27:34 +02:00

208 lines
7.5 KiB
JavaScript

const initializeGDevelopJs = require('../../Binaries/embuild/GDevelop.js/libGD.js');
const { makeMinimalGDJSMock } = require('../TestUtils/GDJSMocks.js');
const {
generateCompiledEventsForLayout,
} = require('../TestUtils/CodeGenerationHelpers.js');
describe('libGD.js - GDJS Scene Code Generation integration tests', function () {
let gd = null;
beforeAll(async () => {
gd = await initializeGDevelopJs();
});
describe('(Scene) variable code generation', () => {
let project = null;
let scene = null;
beforeEach(() => {
project = new gd.ProjectHelper.createNewGDJSProject();
scene = project.insertNewLayout('Scene', 0);
scene.getObjects().insertNewObject(project, '', 'MyObject', 0);
// These variables are "simple" and their type will be known at code generation.
scene.getVariables().insertNew('MyNumberVariable', 0).setValue(123);
scene.getVariables().insertNew('MyStringVariable', 1).setString('Test');
scene
.getVariables()
.insertNew('MyOtherStringVariable', 1)
.setString('SomeChild');
// Use a variable that has a value deep inside a structure - so code generation
// does not know its type and will issue a `getAsNumberOrString`.
scene
.getVariables()
.insertNew('MyOtherStructureVariable', 1)
.getChild('Child')
.getChild('SubChild')
.setString('SomeOtherChild');
const structureVariable = scene
.getVariables()
.insertNew('MyStructureVariable', 2);
// Make a structure that we will address using other variables.
structureVariable.getChild('Test').setValue(1);
structureVariable.getChild('123').setValue(2);
structureVariable.getChild('42').setValue(4);
structureVariable.getChild('MyObject').setValue(8);
structureVariable.getChild('SomeChild').getChild('Test').setValue(16);
structureVariable.getChild('SomeChild').getChild('123').setValue(32);
structureVariable.getChild('SomeChild').getChild('42').setValue(64);
structureVariable
.getChild('SomeChild')
.getChild('MyObject')
.setValue(128);
structureVariable
.getChild('SomeChild')
.getChild('SomeOtherChild')
.getChild('Test')
.setValue(256);
structureVariable
.getChild('SomeChild')
.getChild('SomeOtherChild')
.getChild('123')
.setValue(512);
structureVariable
.getChild('SomeChild')
.getChild('SomeOtherChild')
.getChild('42')
.setValue(1024);
structureVariable
.getChild('SomeChild')
.getChild('SomeOtherChild')
.getChild('MyObject')
.setValue(2048);
});
afterEach(() => {
project.delete();
});
it('generates code for structure variables accessed by another variable (1 level)', function () {
const serializedLayoutEvents = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarScene' },
parameters: [
'Counter',
'+',
'MyStructureVariable[MyStringVariable] + MyStructureVariable[MyNumberVariable] + MyStructureVariable[MyObject.X()] + MyStructureVariable[MyObject.ObjectName()]',
],
},
],
events: [],
},
]);
scene.getEvents().unserializeFrom(project, serializedLayoutEvents);
const runCompiledEvents = generateCompiledEventsForLayout(
gd,
project,
scene
);
const serializedSceneElement = new gd.SerializerElement();
scene.serializeTo(serializedSceneElement);
const { gdjs, runtimeScene } = makeMinimalGDJSMock({
sceneData: JSON.parse(gd.Serializer.toJSON(serializedSceneElement)),
});
serializedSceneElement.delete();
const myObjectInstance = runtimeScene.createObject('MyObject');
myObjectInstance.setX(42);
runCompiledEvents(gdjs, runtimeScene);
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
expect(runtimeScene.getVariables().get('Counter').getAsNumber()).toBe(
1 + 2 + 4 + 8
);
});
it('generates code for structure variables accessed by another variable (2 levels)', function () {
const serializedLayoutEvents = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarScene' },
parameters: [
'Counter',
'+',
'MyStructureVariable.SomeChild[MyStringVariable] + MyStructureVariable.SomeChild[MyNumberVariable] + MyStructureVariable.SomeChild[MyObject.X()] + MyStructureVariable.SomeChild[MyObject.ObjectName()]',
],
},
],
events: [],
},
]);
scene.getEvents().unserializeFrom(project, serializedLayoutEvents);
const runCompiledEvents = generateCompiledEventsForLayout(
gd,
project,
scene
);
const serializedSceneElement = new gd.SerializerElement();
scene.serializeTo(serializedSceneElement);
const { gdjs, runtimeScene } = makeMinimalGDJSMock({
sceneData: JSON.parse(gd.Serializer.toJSON(serializedSceneElement)),
});
serializedSceneElement.delete();
const myObjectInstance = runtimeScene.createObject('MyObject');
myObjectInstance.setX(42);
runCompiledEvents(gdjs, runtimeScene);
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
expect(runtimeScene.getVariables().get('Counter').getAsNumber()).toBe(
16 + 32 + 64 + 128
);
});
it('generates code for structure variables accessed by another variable (3 levels)', function () {
const serializedLayoutEvents = gd.Serializer.fromJSObject([
{
type: 'BuiltinCommonInstructions::Standard',
conditions: [],
actions: [
{
type: { value: 'ModVarScene' },
parameters: [
'Counter',
'+',
'MyStructureVariable[MyOtherStringVariable][MyOtherStructureVariable.Child.SubChild][MyStringVariable] +MyStructureVariable[MyOtherStringVariable][MyOtherStructureVariable.Child.SubChild][MyNumberVariable] + MyStructureVariable[MyOtherStringVariable][MyOtherStructureVariable.Child.SubChild][MyObject.X()] + MyStructureVariable[MyOtherStringVariable][MyOtherStructureVariable.Child.SubChild][MyObject.ObjectName()]',
],
},
],
events: [],
},
]);
scene.getEvents().unserializeFrom(project, serializedLayoutEvents);
const runCompiledEvents = generateCompiledEventsForLayout(
gd,
project,
scene
);
const serializedSceneElement = new gd.SerializerElement();
scene.serializeTo(serializedSceneElement);
const { gdjs, runtimeScene } = makeMinimalGDJSMock({
sceneData: JSON.parse(gd.Serializer.toJSON(serializedSceneElement)),
});
serializedSceneElement.delete();
const myObjectInstance = runtimeScene.createObject('MyObject');
myObjectInstance.setX(42);
runCompiledEvents(gdjs, runtimeScene);
expect(runtimeScene.getVariables().has('Counter')).toBe(true);
expect(runtimeScene.getVariables().get('Counter').getAsNumber()).toBe(
256 + 512 + 1024 + 2048
);
});
});
});