Files
Florian Rival 17443587b9 Add Else event (#8216)
* This is not finished yet:
  - Documentation needs to be written.
  - Menu item (and shortcut?) to quickly toggle between a standard event and a else event must be added so it's easy to switch from one to the other.
  - Design must be adapted to make it clearer that the else event is "linked" to the previous one and is not run if the previous event is run.
2026-02-07 17:15:01 +01:00

797 lines
29 KiB
JavaScript

const path = require('path');
const {
makeFakeAbstractFileSystem,
} = require('../TestUtils/FakeAbstractFileSystem');
const initializeGDevelopJs = require('../../Binaries/embuild/GDevelop.js/libGD.js');
const { makeTestExtensions } = require('../TestUtils/TestExtensions');
describe('libGD.js - GDJS related tests', function () {
let gd = null;
beforeAll(async () => {
gd = await initializeGDevelopJs();
makeTestExtensions(gd);
});
describe('Exporter', () => {
// Fake files to simulate a file system (see tests below).
const fakeIndexHtmlContent = `<html>
<head>
<style>
/* GDJS_CUSTOM_STYLE */
</style>
<!-- GDJS_CODE_FILES -->
<body>
<!-- GDJS_CUSTOM_HTML -->
</body>
</head>
</html>`;
const fakeConfigXmlContent = `
<widget id="GDJS_PACKAGENAME" version="GDJS_PROJECTVERSION">
<name>GDJS_PROJECTNAME</name>
<platform name="android">
<!-- GDJS_ICONS_ANDROID -->
</platform>
<platform name="ios">
<!-- GDJS_ICONS_IOS -->
</platform>
<!-- GDJS_EXTENSION_CORDOVA_DEPENDENCY -->
</widget>`;
const fakePackageJsonContent = `
{
"name": "GDJS_GAME_MANGLED_NAME",
"displayName": "GDJS_GAME_NAME",
"version": "GDJS_GAME_VERSION",
"description": "GDJS_GAME_NAME",
"author": "GDJS_GAME_AUTHOR"
}`;
it('properly exports HTML5 files', () => {
// Create a simple project
const project = gd.ProjectHelper.createNewGDJSProject();
project.setName('My great project with spaces and "quotes"!');
project.setDescription(
'A nice project\nwith line breaks in the description.'
);
project.setVersion('1.2.3');
// Prepare a fake file system
var fs = makeFakeAbstractFileSystem(gd, {
'/fake-gdjs-root/Runtime/index.html': fakeIndexHtmlContent,
'/fake-gdjs-root/Runtime/Electron/LICENSE.GDevelop.txt': '',
});
// Export and check the content of written files.
const exporter = new gd.Exporter(fs, '/fake-gdjs-root');
const exportOptions = new gd.ExportOptions(project, '/fake-export-dir');
expect(exporter.exportWholePixiProject(exportOptions)).toBe(true);
exportOptions.delete();
exporter.delete();
// Check the index.html contains the include files.
expect(fs.writeToFile.mock.calls[1][0]).toBe(
'/fake-export-dir/index.html'
);
expect(fs.writeToFile.mock.calls[1][1]).toContain('gd.js');
expect(fs.writeToFile.mock.calls[1][1]).toContain(
'affinetransformation.js'
);
expect(fs.writeToFile.mock.calls[1][1]).toContain(
'pixi-renderers/runtimescene-pixi-renderer.js'
);
expect(fs.writeToFile.mock.calls[1][1]).toContain('data.js');
// Check the webmanifest was properly generated.
expect(fs.writeToFile.mock.calls[2][0]).toBe(
'/fake-export-dir/manifest.webmanifest'
);
expect(() => JSON.parse(fs.writeToFile.mock.calls[2][1])).not.toThrow();
expect(JSON.parse(fs.writeToFile.mock.calls[2][1])).toEqual({
name: 'My great project with spaces and "quotes"!',
short_name: 'My great project with spaces and "quotes"!',
id: 'com.example.gamename',
description: 'A nice project\nwith line breaks in the description.',
orientation: 'landscape',
start_url: './index.html',
display: 'standalone',
background_color: 'black',
categories: ['games', 'entertainment'],
icons: [],
});
});
it('properly exports Cordova files', () => {
// Create a simple project
const project = gd.ProjectHelper.createNewGDJSProject();
project.setName(
'My great project with spaces and "quotes" and (parentheses)!'
);
project.setVersion('1.2.3');
// Prepare a fake file system
var fs = makeFakeAbstractFileSystem(gd, {
'/fake-gdjs-root/Runtime/Cordova/www/index.html': fakeIndexHtmlContent,
'/fake-gdjs-root/Runtime/Cordova/config.xml': fakeConfigXmlContent,
'/fake-gdjs-root/Runtime/Cordova/package.json': fakePackageJsonContent,
'/fake-gdjs-root/Runtime/Cordova/www/LICENSE.GDevelop.txt': '',
});
// Export and check the content of written files.
const exporter = new gd.Exporter(fs, '/fake-gdjs-root');
const exportOptions = new gd.ExportOptions(project, '/fake-export-dir');
exportOptions.setTarget('cordova');
expect(exporter.exportWholePixiProject(exportOptions)).toBe(true);
exportOptions.delete();
exporter.delete();
expect(fs.writeToFile).toHaveBeenCalledWith(
'/fake-export-dir/config.xml',
`
<widget id="com.example.gamename" version="1.2.3">
<name>My great project with spaces and &quot;quotes&quot; and parentheses!</name>
<platform name="android">
</platform>
<platform name="ios">
</platform>
</widget>`
);
expect(fs.writeToFile).toHaveBeenCalledWith(
'/fake-export-dir/package.json',
`
{
\"name\": \"my_32great_32project_32with_32spaces_32and_32_34quotes_34_32and_32_40parentheses_41_33\",
\"displayName\": \"My great project with spaces and \\\"quotes\\\" and (parentheses)!\",
\"version\": \"1.2.3\",
\"description\": \"My great project with spaces and \\\"quotes\\\" and (parentheses)!\",
\"author\": \"\"
}`
);
});
it('properly exports Cordova plugins config if required by an extension', () => {
// Create a project with some content using the AdMob extension.
const project = gd.ProjectHelper.createNewGDJSProject();
project.setName('My great project with spaces and "quotes"!');
project.setVersion('1.2.3');
project
.getExtensionProperties()
.setValue('AdMob', 'AdMobAppIdAndroid', 'my android app id');
const layout = project.insertNewLayout('Scene', 0);
const event = layout
.getEvents()
.insertNewEvent(project, 'BuiltinCommonInstructions::Standard', 0);
const action = new gd.Instruction();
action.setType('AdMob::ShowInterstitial');
gd.asStandardEvent(event).getActions().insert(action, 0);
// Prepare a fake file system
var fs = makeFakeAbstractFileSystem(gd, {
'/fake-gdjs-root/Runtime/Cordova/www/index.html': fakeIndexHtmlContent,
'/fake-gdjs-root/Runtime/Cordova/config.xml': fakeConfigXmlContent,
'/fake-gdjs-root/Runtime/Cordova/package.json': fakePackageJsonContent,
'/fake-gdjs-root/Runtime/Cordova/www/LICENSE.GDevelop.txt': '',
});
// Export and check the content of written files.
const exporter = new gd.Exporter(fs, '/fake-gdjs-root');
const exportOptions = new gd.ExportOptions(project, '/fake-export-dir');
exportOptions.setTarget('cordova');
expect(exporter.exportWholePixiProject(exportOptions)).toBe(true);
exportOptions.delete();
exporter.delete();
expect(fs.writeToFile).toHaveBeenCalledWith(
'/fake-export-dir/config.xml',
`
<widget id="com.example.gamename" version="1.2.3">
<name>My great project with spaces and &quot;quotes&quot;!</name>
<platform name="android">
</platform>
<platform name="ios">
</platform>
<plugin name=\"gdevelop-cordova-admob-plus\" spec=\"0.43.0\">
<variable name=\"APP_ID_ANDROID\" value=\"my android app id\" />
</plugin>
</widget>`
);
expect(fs.writeToFile).toHaveBeenCalledWith(
'/fake-export-dir/package.json',
`
{
\"name\": \"my_32great_32project_32with_32spaces_32and_32_34quotes_34_33\",
\"displayName\": \"My great project with spaces and \\\"quotes\\\"!\",
\"version\": \"1.2.3\",
\"description\": \"My great project with spaces and \\\"quotes\\\"!\",
\"author\": \"\"
}`
);
});
});
describe('LayoutCodeGenerator', () => {
it('can generate code for a layout', function () {
const project = gd.ProjectHelper.createNewGDJSProject();
const layout = project.insertNewLayout('Scene', 0);
// Create a repeat event with a trigger once
const evt = layout
.getEvents()
.insertNewEvent(project, 'BuiltinCommonInstructions::Repeat', 0);
gd.asRepeatEvent(evt).setRepeatExpressionPlainString('5+4+3+2+1');
const condition = new gd.Instruction();
condition.setType('BuiltinCommonInstructions::Once');
gd.asRepeatEvent(evt).getConditions().insert(condition, 0);
condition.delete();
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
const diagnosticReport = new gd.DiagnosticReport();
const code = layoutCodeGenerator.generateLayoutCompleteCode(
layout,
new gd.SetString(),
diagnosticReport,
true
);
diagnosticReport.delete();
layoutCodeGenerator.delete();
project.delete();
// The loop is using a counter somewhere
expect(code).toMatch('repeatCount');
// Trigger once is used in a condition
expect(code).toMatch('runtimeScene.getOnceTriggers().triggerOnce');
});
it('can generate code for else events', function () {
const project = gd.ProjectHelper.createNewGDJSProject();
const layout = project.insertNewLayout('Scene', 0);
const standardEvent = layout
.getEvents()
.insertNewEvent(project, 'BuiltinCommonInstructions::Standard', 0);
const elseEvent = layout
.getEvents()
.insertNewEvent(project, 'BuiltinCommonInstructions::Else', 1);
const standardCondition = new gd.Instruction();
standardCondition.setType('BuiltinCommonInstructions::Always');
gd.asStandardEvent(standardEvent).getConditions().insert(standardCondition, 0);
standardCondition.delete();
const standardAction = new gd.Instruction();
standardAction.setType('BuiltinCommonInstructions::SetNumberVariable');
standardAction.setParametersCount(3);
standardAction.setParameter(0, 'MyVariable');
standardAction.setParameter(1, '=');
standardAction.setParameter(2, '1');
gd.asStandardEvent(standardEvent).getActions().insert(standardAction, 0);
standardAction.delete();
const elseAction = new gd.Instruction();
elseAction.setType('BuiltinCommonInstructions::SetNumberVariable');
elseAction.setParametersCount(3);
elseAction.setParameter(0, 'MyVariable');
elseAction.setParameter(1, '=');
elseAction.setParameter(2, '2');
gd.asElseEvent(elseEvent).getActions().insert(elseAction, 0);
elseAction.delete();
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
const diagnosticReport = new gd.DiagnosticReport();
const code = layoutCodeGenerator.generateLayoutCompleteCode(
layout,
new gd.SetString(),
diagnosticReport,
true
);
diagnosticReport.delete();
layoutCodeGenerator.delete();
project.delete();
expect(code).toMatch('elseEventsChainSatisfied');
});
it('does not generate code for improperly set up actions/conditions', function () {
const project = gd.ProjectHelper.createNewGDJSProject();
const layout = project.insertNewLayout('Scene', 0);
const evt = layout
.getEvents()
.insertNewEvent(project, 'BuiltinCommonInstructions::Standard', 0);
layout.getObjects().insertNewObject(project, 'Sprite', 'MyObject', 0);
layout
.getObjects()
.insertNewObject(project, 'TextObject::Text', 'MyTextObject', 0);
layout
.getObjects()
.insertNewObject(
project,
'FakeObjectWithUnsupportedCapability::FakeObjectWithUnsupportedCapability',
'MyFakeObjectWithUnsupportedCapability',
0
);
// Valid action (to check code generation is done).
{
const action = new gd.Instruction();
action.setType('ChangeAnimation');
action.setParametersCount(4);
action.setParameter(0, 'MyObject');
action.setParameter(1, '=');
action.setParameter(2, '2');
gd.asStandardEvent(evt).getActions().insert(action, 0);
action.delete();
}
// Action with mismatched object type.
{
const mismatchedObjectTypeAction = new gd.Instruction();
mismatchedObjectTypeAction.setType('ChangeAnimation');
mismatchedObjectTypeAction.setParametersCount(4);
mismatchedObjectTypeAction.setParameter(0, 'MyTextObject');
mismatchedObjectTypeAction.setParameter(1, '=');
mismatchedObjectTypeAction.setParameter(2, '2');
gd.asStandardEvent(evt)
.getActions()
.insert(mismatchedObjectTypeAction, 1);
mismatchedObjectTypeAction.delete();
}
// Action with an unknown object.
{
const unknownObjectAction = new gd.Instruction();
unknownObjectAction.setType('ChangeAnimation');
unknownObjectAction.setParametersCount(4);
unknownObjectAction.setParameter(0, 'UnknownObject');
unknownObjectAction.setParameter(1, '=');
unknownObjectAction.setParameter(2, '2');
gd.asStandardEvent(evt).getActions().insert(unknownObjectAction, 2);
unknownObjectAction.delete();
}
// Action that is unknown.
{
const unknownAction = new gd.Instruction();
unknownAction.setType('UnknownExtension::NotExistingInstruction');
unknownAction.setParametersCount(1);
unknownAction.setParameter(0, 'Anything');
gd.asStandardEvent(evt).getActions().insert(unknownAction, 3);
unknownAction.delete();
}
// Action for an object not having the required capability.
{
const unsupportedCapabilityAction = new gd.Instruction();
unsupportedCapabilityAction.setType(
'EffectCapability::EffectBehavior::EnableEffect'
);
unsupportedCapabilityAction.setParametersCount(4);
unsupportedCapabilityAction.setParameter(
0,
'MyFakeObjectWithUnsupportedCapability'
);
unsupportedCapabilityAction.setParameter(1, 'Effect');
unsupportedCapabilityAction.setParameter(1, '"MyEffect"');
unsupportedCapabilityAction.setParameter(2, 'yes');
gd.asStandardEvent(evt)
.getActions()
.insert(unsupportedCapabilityAction, 4);
unsupportedCapabilityAction.delete();
}
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
const diagnosticReport = new gd.DiagnosticReport();
const code = layoutCodeGenerator.generateLayoutCompleteCode(
layout,
new gd.SetString(),
diagnosticReport,
true
);
diagnosticReport.delete();
layoutCodeGenerator.delete();
project.delete();
// Animation is set to 2 for MyObject
expect(code).toMatch(
'gdjs.SceneCode.GDMyObjectObjects1[i].setAnimation(2);'
);
// Check that the action with a wrong object was not generated.
expect(code).toMatch('/* Mismatched object type - skipped. */');
// Check that the action with a wrong object was not generated.
expect(code).toMatch('/* Unknown object - skipped. */');
// Check that the unknown action was not generated.
expect(code).toMatch('/* Unknown instruction - skipped. */');
// Check that the action for an object not having the required capability was not generated.
expect(code).toEqual(
expect.not.stringContaining(
'gdjs.SceneCode.GDMyFakeObjectWithUnsupportedCapabilityObjects1[i].getBehavior("Effect")'
)
);
});
it('does not generate code for improperly set up action/conditions, with groups', function () {
const project = gd.ProjectHelper.createNewGDJSProject();
const layout = project.insertNewLayout('Scene', 0);
const evt = layout
.getEvents()
.insertNewEvent(project, 'BuiltinCommonInstructions::Standard', 0);
layout.getObjects().insertNewObject(project, 'Sprite', 'MySprite', 0);
const obj = layout
.getObjects()
.insertNewObject(
project,
'FakeObjectWithUnsupportedCapability::FakeObjectWithUnsupportedCapability',
'MyFakeObjectWithUnsupportedCapability',
0
);
const group = layout
.getObjects()
.getObjectGroups()
.insertNew('MyGroup', 0);
group.addObject('MySprite');
group.addObject('MyFakeObjectWithUnsupportedCapability');
// Valid action (to check code generation is done).
{
const action = new gd.Instruction();
action.setType('ChangeLayer');
action.setParametersCount(2);
action.setParameter(0, 'MyGroup');
action.setParameter(1, '"New layer"');
gd.asStandardEvent(evt).getActions().insert(action, 0);
action.delete();
}
// Action for an object not having the required capability.
{
const unsupportedCapabilityAction = new gd.Instruction();
unsupportedCapabilityAction.setType(
'EffectCapability::EffectBehavior::EnableEffect'
);
unsupportedCapabilityAction.setParametersCount(4);
unsupportedCapabilityAction.setParameter(0, 'MyGroup');
unsupportedCapabilityAction.setParameter(1, 'Effect');
unsupportedCapabilityAction.setParameter(2, '"MyEffect"');
unsupportedCapabilityAction.setParameter(3, 'yes');
gd.asStandardEvent(evt)
.getActions()
.insert(unsupportedCapabilityAction, 1);
unsupportedCapabilityAction.delete();
}
const layoutCodeGenerator = new gd.LayoutCodeGenerator(project);
const diagnosticReport = new gd.DiagnosticReport();
const code = layoutCodeGenerator.generateLayoutCompleteCode(
layout,
new gd.SetString(),
diagnosticReport,
true
);
diagnosticReport.delete();
layoutCodeGenerator.delete();
project.delete();
// Layer can be changed for both object instances.
expect(code).toMatch(
'gdjs.SceneCode.GDMySpriteObjects1[i].setLayer("New layer");'
);
expect(code).toMatch(
'gdjs.SceneCode.GDMyFakeObjectWithUnsupportedCapabilityObjects1[i].setLayer("New layer");'
);
// Check that the action with an object not having the required capability
// was not generated for this object,
// but generated for the Sprite supporting this capability.
expect(code).toMatch(
'gdjs.SceneCode.GDMySpriteObjects1[i].getBehavior("Effect").enableEffect("MyEffect", true);'
);
expect(code).toEqual(
expect.not.stringContaining(
'gdjs.SceneCode.GDMyFakeObjectWithUnsupportedCapabilityObjects1[i].getBehavior("Effect")'
)
);
});
});
describe('EventsFunctionsExtensionCodeGenerator', () => {
it('can generate code for an events function', function () {
const project = new gd.ProjectHelper.createNewGDJSProject();
const includeFiles = new gd.SetString();
const eventsFunction = new gd.EventsFunction();
// Create a function accepting 4 parameters:
const parameters = eventsFunction.getParameters();
parameters
.insertNewParameter('MyObject', 0)
.setType('objectList')
.setDescription('The first object to be used');
parameters
.insertNewParameter('MyNumber', 1)
.setType('expression')
.setDescription('Some number');
parameters
.insertNewParameter('MySprite', 2)
.setType('objectList')
.setDescription('The second object to be used, a sprite')
.setExtraInfo('Sprite');
parameters
.insertNewParameter('MyString', 3)
.setType('string')
.setDescription('Some string')
.setExtraInfo('Sprite');
// Create a repeat event with...
const eventsList = eventsFunction.getEvents();
const evt = eventsList.insertNewEvent(
project,
'BuiltinCommonInstructions::Repeat',
0
);
gd.asRepeatEvent(evt).setRepeatExpressionPlainString('5+4+3+2+1');
// ...a trigger once condition...
const condition = new gd.Instruction();
condition.setType('BuiltinCommonInstructions::Once');
gd.asRepeatEvent(evt).getConditions().insert(condition, 0);
// ...and an action to update a variable of MyObject
const action = new gd.Instruction();
action.setType('ModVarObjet');
action.setParametersCount(4);
action.setParameter(0, 'MyObject');
action.setParameter(1, 'ObjectVariable');
action.setParameter(2, '+');
action.setParameter(3, '42');
gd.asRepeatEvent(evt).getActions().insert(action, 0);
const action2 = new gd.Instruction();
action2.setType('ModVarObjet');
action2.setParametersCount(4);
action2.setParameter(0, 'MyObject');
action2.setParameter(1, 'ObjectVariable2');
action2.setParameter(2, '=');
action2.setParameter(
3,
'GetArgumentAsNumber("MyNumber") + ToNumber(GetArgumentAsString("MyString"))'
);
gd.asRepeatEvent(evt).getActions().insert(action2, 1);
const namespace = 'gdjs.eventsFunction.myTest';
const extension = new gd.EventsFunctionsExtension();
const eventsFunctionsExtensionCodeGenerator = new gd.EventsFunctionsExtensionCodeGenerator(
project
);
const code = eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
extension,
eventsFunction,
namespace,
includeFiles,
true
);
// Check that the function name is properly generated
expect(code).toMatch(namespace + '.func = function(');
// Check that the context for the events function is here...
expect(code).toMatch('function(runtimeScene, eventsFunctionContext)');
expect(code).toMatch('var eventsFunctionContext =');
// Check that the parameters, with the (optional) context of the parent function,
// are all here
expect(code).toMatch(
'function(runtimeScene, MyObject, MyNumber, MySprite, MyString, parentEventsFunctionContext)'
);
// ...and objects should be able to get queried...
expect(code).toMatch('"MyObject": MyObject');
expect(code).toMatch('"MySprite": MySprite');
// ...and arguments should be able to get queried too:
expect(code).toMatch('if (argName === "MyNumber") return MyNumber;');
expect(code).toMatch('if (argName === "MyString") return MyString;');
// GetArgumentAsString("MyString") should be generated code to query and cast as a string
// the argument
expect(code).toMatch(
'("" + eventsFunctionContext.getArgument("MyString"))'
);
// GetArgumentAsNumber("MyNumber") should be generated code to query and cast as a string
// the argument
expect(code).toMatch(
'(Number(eventsFunctionContext.getArgument("MyNumber")) || 0)'
);
// The loop is using a counter somewhere
expect(code).toMatch('repeatCount');
// Trigger once is used in a condition
expect(code).toMatch(
'eventsFunctionContext.getOnceTriggers().triggerOnce'
);
// A variable has 42 added to it
expect(code).toMatch('getVariables().get("ObjectVariable")).add(42)');
condition.delete();
action.delete();
extension.delete();
});
it('can generate code for an events function, with groups', function () {
const project = new gd.ProjectHelper.createNewGDJSProject();
const includeFiles = new gd.SetString();
const eventsFunction = new gd.EventsFunction();
// Create a function accepting 2 parameters:
const parameters = eventsFunction.getParameters();
parameters
.insertNewParameter('MyObject', 0)
.setType('objectList')
.setDescription('The first object to be used');
parameters
.insertNewParameter('MySprite', 1)
.setType('objectList')
.setDescription('The second object to be used, a sprite')
.setExtraInfo('Sprite');
// And with a group:
const group = eventsFunction.getObjectGroups().insertNew('MyGroup', 0);
group.addObject('MyObject');
group.addObject('MySprite');
// Create a repeat event with...
const eventsList = eventsFunction.getEvents();
const evt = eventsList.insertNewEvent(
project,
'BuiltinCommonInstructions::Repeat',
0
);
gd.asRepeatEvent(evt).setRepeatExpressionPlainString('5+4+3+2+1');
// ...an action to update a variable of the group of objects
const action = new gd.Instruction();
action.setType('ModVarObjet');
action.setParametersCount(4);
action.setParameter(0, 'MyGroup');
action.setParameter(1, 'ObjectVariable');
action.setParameter(2, '+');
action.setParameter(3, '42');
gd.asRepeatEvent(evt).getActions().insert(action, 0);
const namespace = 'gdjs.eventsFunction.myTest';
const eventsFunctionsExtensionCodeGenerator = new gd.EventsFunctionsExtensionCodeGenerator(
project
);
const code = eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
new gd.EventsFunctionsExtension(),
eventsFunction,
namespace,
includeFiles,
true
);
// Check that the function name is properly generated
expect(code).toMatch(namespace + '.func = function(');
// Check that the context for the events function is here...
expect(code).toMatch('function(runtimeScene, eventsFunctionContext)');
expect(code).toMatch('var eventsFunctionContext =');
// Check that the parameters, with the (optional) context of the parent function,
// are all here
expect(code).toMatch(
'function(runtimeScene, MyObject, MySprite, parentEventsFunctionContext)'
);
// ...and objects should be able to get queried...
expect(code).toMatch('"MyObject": MyObject');
expect(code).toMatch('"MySprite": MySprite');
// Variables of both MyObject and MySprite should have 42 added:
expect(code).toMatch(
'GDMyObjectObjects2[i].getVariables().get("ObjectVariable")).add(42)'
);
expect(code).toMatch(
'GDMySpriteObjects2[i].getVariables().get("ObjectVariable")).add(42)'
);
action.delete();
});
});
describe('TextObject', function () {
it('should expose TextObject specific methods', function () {
var object = new gd.TextObject('MyTextObject');
object.setText('Hello');
object.setFontName('Hello.ttf');
object.setCharacterSize(10);
object.setBold(true);
object.setColor('1;2;3');
expect(object.getText()).toBe('Hello');
expect(object.getFontName()).toBe('Hello.ttf');
expect(object.getCharacterSize()).toBe(10);
expect(object.isBold()).toBe(true);
expect(object.getColor()).toBe('1;2;3');
});
});
describe('TiledSpriteObject', function () {
it('should expose TiledSpriteObject specific methods', function () {
var object = new gd.TiledSpriteObject('MyTiledSpriteObject');
object.setTexture('MyImageName');
expect(object.getTexture()).toBe('MyImageName');
});
});
describe('PanelSpriteObject', function () {
it('should expose PanelSpriteObject specific methods', function () {
var object = new gd.PanelSpriteObject('MyPanelSpriteObject');
object.setTexture('MyImageName');
expect(object.getTexture()).toBe('MyImageName');
});
});
describe('ShapePainterObject', function () {
it('should expose ShapePainterObject specific methods', function () {
var object = new gd.ShapePainterObject('MyShapePainterObject');
object.setCoordinatesAbsolute();
expect(object.areCoordinatesAbsolute()).toBe(true);
object.setCoordinatesRelative();
expect(object.areCoordinatesAbsolute()).toBe(false);
});
});
describe('ShapePainterObject', function () {
it('should expose ShapePainterObject specific methods', function () {
var object = new gd.ShapePainterObject('MyShapePainterObject');
object.setClearBetweenFrames(true);
expect(object.isClearedBetweenFrames()).toBe(true);
object.setClearBetweenFrames(false);
expect(object.isClearedBetweenFrames()).toBe(false);
});
});
describe('TextEntryObject', function () {
it('should expose TextEntryObject', function () {
var object = new gd.TextEntryObject('MyTextEntryObject');
});
});
describe('ParticleEmitterObject', function () {
it('should expose ParticleEmitterObject', function () {
var object = new gd.ParticleEmitterObject('MyParticleEmitterObject');
});
});
describe('JsCodeEvent', function () {
it('can store its code', function () {
var event = new gd.JsCodeEvent();
event.setInlineCode('console.log("Hello world");');
expect(event.getInlineCode()).toBe('console.log("Hello world");');
});
it('can store the objects to pass as parameter', function () {
var event = new gd.JsCodeEvent();
event.setParameterObjects('MyObject');
expect(event.getParameterObjects()).toBe('MyObject');
});
it("can store if it's expanded or not", function () {
var event = new gd.JsCodeEvent();
expect(event.isEventsSheetExpanded()).toBe(false);
event.setEventsSheetExpanded(true);
expect(event.isEventsSheetExpanded()).toBe(true);
});
it('can be cloned', function () {
var event = new gd.JsCodeEvent();
event.setInlineCode('console.log("Hello world 2");');
event.setParameterObjects('MyObject2');
var cloneEvent = event.clone();
expect(cloneEvent.getParameterObjects()).toBe('MyObject2');
expect(cloneEvent.getInlineCode()).toBe('console.log("Hello world 2");');
});
});
});