chore(tests): test running procedure events (#6627)

* chore: define necessary events

* chore: cleanup test organization

* chore: cleanup comment

* chore: move assertEventFiredShallow to test helpers

* chore: add tests for running the procedure change return events

* chore: work on tests??

* chore: add tests for running the change return events

* chore: add tests for running enable events

* chore: add tests for procedure rename events

* chore: add tests for renaming procedure parameters

* chore: add tests for running procedure create events

* chore: add tests for running procedure parameter create events

* chore: add tests for running procedure delete events

* chore: add tests for running procedure parameter delete events

* chore: skip all tests for running procedure events
This commit is contained in:
Beka Westberg
2022-11-18 16:01:41 -08:00
committed by GitHub
parent a1eb42307f
commit 7b055dbc7e
12 changed files with 1527 additions and 53 deletions

View File

@@ -113,10 +113,10 @@ export abstract class Abstract {
* @param _forward True if run forward, false if run backward (undo).
*/
run(_forward: boolean) {
// Defined by subclasses.
// Defined by subclasses. Cannot be abstract b/c UI events do /not/ define
// this.
}
/**
* Get workspace the event belongs to.
*

View File

@@ -0,0 +1,181 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureChangeReturn');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Change Return Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
const DEFAULT_TYPES = null;
const NON_DEFAULT_TYPES = [];
setup(function() {
this.createProcedureModel = (id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, 'test name', id);
};
this.createEventToState = (procedureModel) => {
return new Blockly.Events.ProcedureChangeReturn(
this.workspace,
procedureModel,
procedureModel.getReturnTypes());
};
});
suite('forward (redo)', function() {
test('the procedure with the matching ID has its return set', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setReturnTypes(NON_DEFAULT_TYPES);
const event = this.createEventToState(final);
this.procedureMap.add(initial);
event.run(true /* forward */);
chai.assert.equal(
initial.getReturnTypes(),
final.getReturnTypes(),
"Expected the procedure's return type to be toggled");
});
test('changing the return fires a change return event', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setReturnTypes(NON_DEFAULT_TYPES);
const event = this.createEventToState(final);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureChangeReturn,
{
model: initial,
oldTypes: DEFAULT_TYPES,
},
this.workspace.id);
});
test('noop return changes do not fire change return events', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
const event = this.createEventToState(final);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureChangeReturn,
{},
this.workspace.id);
});
test(
'attempting to change the return of a procedure that ' +
'does not exist in the map throws',
function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
const event = this.createEventToState(final);
chai.assert.throws(() => {
event.run(true /* forward */);
});
});
});
suite('backward (undo)', function() {
test('the procedure with the matching ID has its return set', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setReturnTypes(NON_DEFAULT_TYPES);
undoable.setReturnTypes(NON_DEFAULT_TYPES);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
event.run(false /* backward */);
chai.assert.equal(
initial.getReturnTypes(),
DEFAULT_TYPES,
"Expected the procedure's return type to be toggled");
});
test('changing the return fires a change return event', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setReturnTypes(NON_DEFAULT_TYPES);
undoable.setReturnTypes(NON_DEFAULT_TYPES);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureChangeReturn,
{
model: initial,
oldTypes: DEFAULT_TYPES,
},
this.workspace.id);
});
test('noop return changes do not fire change return events', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
undoable.setReturnTypes(NON_DEFAULT_TYPES);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureChangeReturn,
{},
this.workspace.id);
});
test(
'attempting to change the return of a procedure that ' +
'does not exist throws',
function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setReturnTypes(NON_DEFAULT_TYPES);
undoable.setReturnTypes(NON_DEFAULT_TYPES);
const event = this.createEventToState(undoable);
chai.assert.throws(() => {
event.run(false /* backward */);
});
});
});
});
});

View File

@@ -0,0 +1,155 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureCreate');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Create Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
setup(function() {
this.createProcedureModel = (name, id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, name, id);
};
this.createEventToState = (procedureModel) => {
return new Blockly.Events.ProcedureCreate(this.workspace, procedureModel);
};
});
suite('forward', function() {
test('a procedure model is created if it does not exist', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
event.run(true /* forward */);
const createdProc = this.procedureMap.get('test id');
chai.assert.isDefined(createdProc, 'Expected the procedure to exist');
chai.assert.equal(
createdProc.getName(),
model.getName(),
"Expected the procedure's name to match the model");
chai.assert.equal(
createdProc.getId(),
model.getId(),
"Expected the procedure's id to match the model");
});
test('creating a procedure model fires a create event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureCreate,
{model: this.procedureMap.get('testid')},
this.workspace.id);
});
test(
'a procedure model is not created if a model with a ' +
'matching ID exists',
function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
event.run(true /* forward */);
chai.assert.equal(
this.procedureMap.get('test id'),
model,
'Expected the model in the procedure map to be the same ' +
'as the original model');
});
test('not creating a model does not fire a create event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureCreate,
{},
this.workspace.id);
});
});
suite('backward', function() {
test(
'a procedure model is deleted if a model with a matching ID exists',
function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
event.run(false /* backward */);
chai.assert.isUndefined(
this.procedureMap.get('test id'),
'Expected the procedure to be deleted');
});
test('deleting a model fires a delete event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{model},
this.workspace.id);
});
test.skip(
'a model is not deleted if no model with a matching ID exists',
function() {
// TODO: Do we want this to throw? warn? do nothing?
});
test('not deleting a model does not fire a delete event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{},
this.workspace.id);
});
});
});
});

View File

@@ -0,0 +1,156 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureDelete');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Delete Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
setup(function() {
this.createProcedureModel = (name, id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, name, id);
};
this.createEventToState = (procedureModel) => {
return new Blockly.Events.ProcedureDelete(
this.workspace, procedureModel);
};
});
suite('forward', function() {
test(
'a procedure model is deleted if a model with a matching ID exists',
function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
event.run(true /* forward */);
chai.assert.isUndefined(
this.procedureMap.get('test id'),
'Expected the procedure to be deleted');
});
test('deleting a model fires a delete event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{model},
this.workspace.id);
});
test(
'a model is not deleted if if nodel with a matching ID exists',
function() {
// TODO: Figure out what we want to do here.
});
test('not deleting a model does not fire a delete event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{},
this.workspace.id);
});
});
suite('backward', function() {
test('a procedure model is created if it does not exist', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
event.run(false /* backward */);
const createdProc = this.procedureMap.get('test id');
chai.assert.isDefined(createdProc, 'Expected the procedure to exist');
chai.assert.equal(
createdProc.getName(),
model.getName(),
"Expected the procedure's name to match the model");
chai.assert.equal(
createdProc.getId(),
model.getId(),
"Expected the procedure's id to match the model");
});
test('creating a procedure model fires a create event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureCreate,
{model: this.procedureMap.get('testid')},
this.workspace.id);
});
test(
'a procedure model is not created if a model with a ' +
'matching ID exists',
function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
event.run(false /* backward */);
chai.assert.equal(
this.procedureMap.get('test id'),
model,
'Expected the model in the procedure map to be the same ' +
'as the original model');
});
test('not creating a model does not fire a create event', function() {
const model = this.createProcedureModel('test name', 'test id');
const event = this.createEventToState(model);
this.procedureMap.add(model);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureCreate,
{},
this.workspace.id);
});
});
});
});

View File

@@ -0,0 +1,175 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureEnable');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Enable Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
setup(function() {
this.createProcedureModel = (id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, 'test name');
};
this.createEventToState = (procedureModel) => {
return new Blockly.Events.ProcedureEnable(procedureModel);
};
});
suite('forward', function() {
test('the procedure with the matching ID is toggled', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setEnabled(!final.getEnabled()); // Set it to the non-default.
const event = this.createEventToState(final);
this.procedureMap.add(initial);
event.run(true /* forward */);
chai.assert.equal(
initial.getEnabled(),
final.getEnabled(),
"Expected the procedure's enabled state to be flipped");
});
test('toggling a procedure fires an enable event', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setEnabled(!final.getEnabled()); // Set it to the non-default.
const event = this.createEventToState(final);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureEnable,
{model: initial},
this.workspace.id);
});
test('noop toggles do not fire enable events', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
const event = this.createEventToState(final);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureEnable,
this.workspace.id);
});
test(
'attempting to toggle a procedure that does not exist throws',
function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setEnabled(!final.getEnabled()); // Set it to the non-default.
const event = this.createEventToState(final);
chai.assert.throws(() => {
event.run(true /* forward */);
});
});
});
suite('backward', function() {
test('the procedure with the matching ID is toggled', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
// Set them to be non-default.
const defaultEnabled = initial.getEnabled();
initial.setEnabled(!defaultEnabled);
undoable.setEnabled(!defaultEnabled);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
event.run(false /* backward */);
chai.assert.equal(
initial.getEnabled(),
defaultEnabled,
"Expected the procedure's enabled state to be flipped");
});
test('toggling a procedure fires an enable event', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
// Set them to be non-default.
const defaultEnabled = initial.getEnabled();
initial.setEnabled(!defaultEnabled);
undoable.setEnabled(!defaultEnabled);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureEnable,
{model: initial},
this.workspace.id);
});
test('noop toggles do not fire enable events', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
// Set them to be non-default.
const defaultEnabled = initial.getEnabled();
undoable.setEnabled(!defaultEnabled);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureEnable,
{},
this.workspace.id);
});
test(
'attempting to toggle a procedure that does not exist throws',
function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
// Set them to be non-default.
const defaultEnabled = initial.getEnabled();
initial.setEnabled(!defaultEnabled);
undoable.setEnabled(!defaultEnabled);
const event = this.createEventToState(undoable);
chai.assert.throws(() => {
event.run(false /* backward */);
});
});
});
});
});

View File

@@ -0,0 +1,200 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureParameterCreate');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Parameter Create Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
setup(function() {
this.createProcedureModel = (name, id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, name, id);
};
this.createProcedureAndParameter =
(procName, procId, paramName, paramId) => {
const param = new Blockly.procedures.ObservableParameterModel(
this.workspace, procName, paramId);
const proc = new Blockly.procedures.ObservableProcedureModel(
this.workspace, paramName, procId)
.insertParameter(param, 0);
return {param, proc};
};
this.createEventToState = (procedureModel, parameterModel) => {
return new Blockly.Events.ProcedureParameterCreate(
this.workspace, procedureModel, parameterModel);
};
});
suite('forward', function() {
test('a parameter is inserted if it does not exist', function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
const actualProc = this.createProcedureModel('test name', 'test id');
this.procedureMap.add(actualProc);
event.run(true /* forward */);
const createdParam = actualProc.getParameter(0);
chai.assert.isDefined(createdParam, 'Expected the parameter to exist');
chai.assert.equal(
createdParam.getName(),
modelParam.getName(),
"Expected the parameter's name to match the model");
chai.assert.equal(
createdParam.getId(),
modelParam.getId(),
"Expected the parameter's id to match the model");
});
test('inserting a parameter fires a create event', function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
const actualProc = this.createProcedureModel('test name', 'test id');
this.procedureMap.add(actualProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterCreate,
{
model: actualProc,
parameter: actualProc.getParameter(0),
index: 0,
},
this.workspace.id);
});
test(
'a parameter is not created if a parameter with a ' +
'matching ID and index already exists',
function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
this.procedureMap.add(modelProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
const actualProc = this.procedureMap.get('test id');
chai.assert.equal(
actualProc,
modelProc,
'Expected the procedure in the procedure map to not have changed');
chai.assert.equal(
actualProc.getParameter(0),
modelParam,
'Expected the parameter to not have changed');
});
test(
'not creating a parameter model does not fire a create event',
function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
this.procedureMap.add(modelProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureParameterCreate,
{},
this.workspace.id);
});
});
suite('backward', function() {
test('a parameter is removed if it exists', function() {
const {param, proc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(proc, param);
this.procedureMap.add(proc);
event.run(false /* backward */);
chai.assert.isUndefined(
proc.getParameter(0),
'Expected the parameter to be deleted');
});
test('removing a parameter fires a delete event', function() {
const {param, proc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(proc, param);
this.procedureMap.add(proc);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterDelete,
{
model: proc,
parameter: param,
index: 0,
},
this.workspace.id);
});
test(
'a parameter is not deleted if a parameter with a ' +
'matching ID and index does not exist',
function() {
// TODO: Figure out what we want to do in this case.
});
test('not removing a parameter does not fire a delete event', function() {
const {param, proc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(proc, param);
this.procedureMap.add(proc);
proc.deleteParameter(0);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureParameterDelete,
{},
this.workspace.id);
});
});
});
});

View File

@@ -0,0 +1,200 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureParameterDelete');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Parameter Delete Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
setup(function() {
this.createProcedureModel = (name, id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, name, id);
};
this.createProcedureAndParameter =
(procName, procId, paramName, paramId) => {
const param = new Blockly.procedures.ObservableParameterModel(
this.workspace, procName, paramId);
const proc = new Blockly.procedures.ObservableProcedureModel(
this.workspace, paramName, procId)
.insertParameter(param, 0);
return {param, proc};
};
this.createEventToState = (procedureModel, parameterModel) => {
return new Blockly.Events.ProcedureParameterCreate(
this.workspace, procedureModel, parameterModel);
};
});
suite('forward', function() {
test('a parameter is removed if it exists', function() {
const {param, proc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(proc, param);
this.procedureMap.add(proc);
event.run(true /* forward */);
chai.assert.isUndefined(
proc.getParameter(0),
'Expected the parameter to be deleted');
});
test('removing a parameter fires a delete event', function() {
const {param, proc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(proc, param);
this.procedureMap.add(proc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterDelete,
{
model: proc,
parameter: param,
index: 0,
},
this.workspace.id);
});
test(
'a parameter is not deleted if a parameter with a ' +
'matching ID and index does not exist',
function() {
// TODO: Figure out what we want to do in this case.
});
test('not removing a parameter does not fire a delete event', function() {
const {param, proc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(proc, param);
this.procedureMap.add(proc);
proc.deleteParameter(0);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureParameterDelete,
{},
this.workspace.id);
});
});
suite('backward', function() {
test('a parameter is inserted if it does not exist', function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
const actualProc = this.createProcedureModel('test name', 'test id');
this.procedureMap.add(actualProc);
event.run(true /* forward */);
const createdParam = actualProc.getParameter(0);
chai.assert.isDefined(createdParam, 'Expected the parameter to exist');
chai.assert.equal(
createdParam.getName(),
modelParam.getName(),
"Expected the parameter's name to match the model");
chai.assert.equal(
createdParam.getId(),
modelParam.getId(),
"Expected the parameter's id to match the model");
});
test('inserting a parameter fires a create event', function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
const actualProc = this.createProcedureModel('test name', 'test id');
this.procedureMap.add(actualProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterCreate,
{
model: actualProc,
parameter: actualProc.getParameter(0),
index: 0,
},
this.workspace.id);
});
test(
'a parameter is not created if a parameter with a ' +
'matching ID and index already exists',
function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
this.procedureMap.add(modelProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
const actualProc = this.procedureMap.get('test id');
chai.assert.equal(
actualProc,
modelProc,
'Expected the procedure in the procedure map to not have changed');
chai.assert.equal(
actualProc.getParameter(0),
modelParam,
'Expected the parameter to not have changed');
});
test(
'not creating a parameter model does not fire a create event',
function() {
const {param: modelParam, proc: modelProc} =
this.createProcedureAndParameter(
'test name', 'test id', 'test param name', 'test param id');
const event = this.createEventToState(modelProc, modelParam);
this.procedureMap.add(modelProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureParameterCreate,
{},
this.workspace.id);
});
});
});
});

View File

@@ -0,0 +1,206 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureParameterRename');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Parameter Rename Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
const DEFAULT_NAME = 'default';
const NON_DEFAULT_NAME = 'non-default';
setup(function() {
this.createProcedureAndParameter = (procId, paramId) => {
const param = new Blockly.procedures.ObservableParameterModel(
this.workspace, DEFAULT_NAME, paramId);
const proc = new Blockly.procedures.ObservableProcedureModel(
this.workspace, 'test name', procId)
.insertParameter(param, 0);
return {param, proc};
};
this.createEventToState = (procedureModel, parameterModel) => {
return new Blockly.Events.ProcedureRename(
this.workspace,
procedureModel,
parameterModel,
parameterModel.getName());
};
});
suite('forward', function() {
test('the parameter with the matching ID and index is renamed', function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: finalParam, proc: finalProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
finalParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(finalProc, finalParam);
this.procedureMap.add(initialProc);
event.run(true /* forward */);
chai.assert.equal(
initialParam.getName(),
finalParam.getName(),
"Expected the procedure parameter's name to be changed");
});
test('renaming a parameter fires a rename event', function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: finalParam, proc: finalProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
finalParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(finalProc, finalParam);
this.procedureMap.add(initialProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterRename,
{
model: initialProc,
parameter: initialParam,
oldName: DEFAULT_NAME,
},
this.workspace.id);
});
test('noop renames do not fire rename events', function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: finalParam, proc: finalProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const event = this.createEventToState(finalProc, finalParam);
this.procedureMap.add(initialProc);
this.eventSpy.resetHistory();
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureParameterRename,
{},
this.workspace.id);
});
test(
'attempting to rename a parameter that does not exist throws',
function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: finalParam, proc: finalProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
finalParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(finalProc, finalParam);
chai.assert.throws(() => {
event.run(true /* forward */);
});
});
});
suite('backward', function() {
test('the parameter with the matching ID and index is renamed', function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: undoableParam, proc: undoableProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
initialParam.setName(NON_DEFAULT_NAME);
undoableParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoableProc, undoableParam);
this.procedureMap.add(initialProc);
this.eventSpy.resetHistory();
event.run(false /* backward */);
chai.assert.equal(
initialParam.getName(),
DEFAULT_NAME,
"Expected the procedure parameter's name to be changed");
});
test('renaming a parameter fires a rename event', function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: undoableParam, proc: undoableProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
initialParam.setName(NON_DEFAULT_NAME);
undoableParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoableProc, undoableParam);
this.procedureMap.add(initialProc);
this.eventSpy.resetHistory();
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterRename,
{
model: initialProc,
parameter: initialParam,
oldName: NON_DEFAULT_NAME,
},
this.workspace.id);
});
test('noop renames do not fire rename events', function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: undoableParam, proc: undoableProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
undoableParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoableProc, undoableParam);
this.procedureMap.add(initialProc);
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureParameterRename,
{},
this.workspace.id);
});
test(
'attempting to rename a parameter that does not exist throws',
function() {
const {param: initialParam, proc: initialProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
const {param: undoableParam, proc: undoableProc} =
this.createProcedureAndParameter('test procId', 'test paramId');
initialParam.setName(NON_DEFAULT_NAME);
undoableParam.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoableProc, undoableParam);
this.procedureMap.add(initialProc);
chai.assert.throws(() => {
event.run(false /* backward */);
});
});
});
});
});

View File

@@ -0,0 +1,170 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.declareModuleId('Blockly.test.eventProcedureRename');
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
// TODO (#6519): Unskip.
suite.skip('Procedure Rename Event', function() {
setup(function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
this.procedureMap = this.workspace.getProcedureMap();
this.eventSpy = createChangeListenerSpy(this.workspace);
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('running', function() {
const DEFAULT_NAME = 'default';
const NON_DEFAULT_NAME = 'non-default';
setup(function() {
this.createProcedureModel = (id) => {
return new Blockly.procedures.ObservableProcedureModel(
this.workspace, DEFAULT_NAME, id);
};
this.createEventToState = (procedureModel) => {
return new Blockly.Events.ProcedureRename(
this.workspace,
procedureModel,
procedureModel.getName());
};
});
suite('forward', function() {
test('the procedure with the matching ID is renamed', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(final);
this.procedureMap.add(initial);
event.run(true /* forward */);
chai.assert.equal(
initial.getName(),
final.getName(),
"Expected the procedure's name to be changed");
});
test('renaming a procedure fires a rename event', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(final);
this.procedureMap.add(initial);
event.run(true /* forward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureRename,
{model: initial, oldName: DEFAULT_NAME},
this.workspace.id);
});
test('noop renames do not fire rename events', function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
const event = this.createEventToState(final);
this.procedureMap.add(initial);
event.run(true /* forward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureRename,
{},
this.workspace.id);
});
test(
'attempting to rename a procedure that does not exist throws',
function() {
const initial = this.createProcedureModel('test id');
const final = this.createProcedureModel('test id');
final.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(final);
chai.assert.throws(() => {
event.run(true /* forward */);
});
});
});
suite('backward', function() {
test('the procedure with the matching ID is renamed', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setName(NON_DEFAULT_NAME);
undoable.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
event.run(false /* backward */);
chai.assert.equal(
initial.getName(),
DEFAULT_NAME,
"Expected the procedure's name to be changed");
});
test('renaming a procedure fires a rename event', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setName(NON_DEFAULT_NAME);
undoable.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
event.run(false /* backward */);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureRename,
{model: initial, oldName: NON_DEFAULT_NAME},
this.workspace.id);
});
test('noop renames do not fire rename events', function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoable);
this.procedureMap.add(initial);
event.run(false /* backward */);
assertEventNotFired(
this.eventSpy,
Blockly.Events.ProcedureRename,
{},
this.workspace.id);
});
test(
'attempting to rename a procedure that does not exist throws',
function() {
const initial = this.createProcedureModel('test id');
const undoable = this.createProcedureModel('test id');
initial.setName(NON_DEFAULT_NAME);
undoable.setName(NON_DEFAULT_NAME);
const event = this.createEventToState(undoable);
chai.assert.throws(() => {
event.run(false /* backward */);
});
});
});
});
});

View File

@@ -73,6 +73,14 @@
'Blockly.test.eventCommentDelete',
'Blockly.test.eventCommentMove',
'Blockly.test.eventMarkerMove',
'Blockly.test.eventProcedureCreate',
'Blockly.test.eventProcedureDelete',
'Blockly.test.eventProcedureRename',
'Blockly.test.eventProcedureEnable',
'Blockly.test.eventProcedureChangeReturn',
'Blockly.test.eventProcedureParameterCreate',
'Blockly.test.eventProcedureParameterDelete',
'Blockly.test.eventProcedureParameterRename',
'Blockly.test.eventSelected',
'Blockly.test.eventThemeChange',
'Blockly.test.eventToolboxItemSelect',

View File

@@ -5,7 +5,7 @@
*/
import {sharedTestSetup, sharedTestTeardown} from './test_helpers/setup_teardown.js';
import {assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
import {assertEventFiredShallow, assertEventNotFired, createChangeListenerSpy} from './test_helpers/events.js';
goog.declareModuleId('Blockly.test.procedureMap');
@@ -202,25 +202,6 @@ suite('Procedure Map', function() {
});
suite('event firing', function() {
function shallowMatch(expected) {
return (actual) => {
for (const key in expected) {
if (actual[key] !== expected[key]) {
return false;
}
}
return true;
};
}
function assertEventFired(spy, instanceType, properties, workspace) {
properties = {...properties, workspaceId: workspace.id};
sinon.assert.calledWith(
spy,
sinon.match.instanceOf(instanceType)
.and(shallowMatch(properties)));
}
setup(function() {
this.eventSpy = createChangeListenerSpy(this.workspace);
});
@@ -235,11 +216,11 @@ suite('Procedure Map', function() {
new Blockly.procedures.ObservableProcedureModel(this.workspace);
this.procedureMap.set(procedureModel.getId(), procedureModel);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureCreate,
{model: procedureModel},
this.workspace);
this.workspace.id);
});
test(
@@ -264,11 +245,11 @@ suite('Procedure Map', function() {
new Blockly.procedures.ObservableProcedureModel(this.workspace);
this.procedureMap.add(procedureModel);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureCreate,
{model: procedureModel},
this.workspace);
this.workspace.id);
});
test(
@@ -285,7 +266,7 @@ suite('Procedure Map', function() {
this.eventSpy,
Blockly.Events.ProcedureCreate,
{},
this.workspace);
this.workspace.id);
});
});
@@ -296,11 +277,11 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel);
this.procedureMap.delete(procedureModel.getId());
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{model: procedureModel},
this.workspace);
this.workspace.id);
});
test(
@@ -331,21 +312,21 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel3);
this.procedureMap.clear();
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{model: procedureModel1},
this.workspace);
assertEventFired(
this.workspace.id);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{model: procedureModel2},
this.workspace);
assertEventFired(
this.workspace.id);
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureDelete,
{model: procedureModel3},
this.workspace);
this.workspace.id);
});
});
@@ -357,14 +338,14 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel);
procedureModel.setName('new name');
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureRename,
{
model: procedureModel,
oldName: 'test name',
},
this.workspace);
this.workspace.id);
});
test('rename events are not fired if the rename is noop', function() {
@@ -405,11 +386,11 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel);
procedureModel.setEnabled(true);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureEnable,
{model: procedureModel},
this.workspace);
this.workspace.id);
});
test('enable events are fired when a procedure is disabled', function() {
@@ -418,11 +399,11 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel);
procedureModel.setEnabled(false);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureEnable,
{model: procedureModel},
this.workspace);
this.workspace.id);
});
test('enable events are not fired if enabling is noop', function() {
@@ -480,7 +461,7 @@ suite('Procedure Map', function() {
this.workspace, 'test name');
procedureModel.insertParameter(parameterModel, 0);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterCreate,
{
@@ -488,7 +469,7 @@ suite('Procedure Map', function() {
parameter: parameterModel,
index: 0,
},
this.workspace);
this.workspace.id);
});
test(
@@ -545,7 +526,7 @@ suite('Procedure Map', function() {
procedureModel.insertParameter(parameterModel, 0);
procedureModel.deleteParameter(0);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterDelete,
{
@@ -553,7 +534,7 @@ suite('Procedure Map', function() {
parameter: parameterModel,
index: 0,
},
this.workspace);
this.workspace.id);
});
test(
@@ -568,7 +549,7 @@ suite('Procedure Map', function() {
this.eventSpy,
Blockly.Events.ProcedureParameterDelete,
{},
this.workspace);
this.workspace.id);
});
test(
@@ -605,8 +586,7 @@ suite('Procedure Map', function() {
parameterModel.setName('new name');
console.log(this.eventSpy.getCalls());
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureParameterRename,
{
@@ -614,7 +594,7 @@ suite('Procedure Map', function() {
parameter: parameterModel,
oldName: 'test name',
},
this.workspace);
this.workspace.id);
});
test(
@@ -684,14 +664,14 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel);
procedureModel.setReturnTypes([]);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureChangeReturn,
{
model: procedureModel,
oldTypes: null,
},
this.workspace);
this.workspace.id);
});
test(
@@ -704,14 +684,14 @@ suite('Procedure Map', function() {
this.procedureMap.add(procedureModel);
procedureModel.setReturnTypes(null);
assertEventFired(
assertEventFiredShallow(
this.eventSpy,
Blockly.Events.ProcedureChangeReturn,
{
model: procedureModel,
oldTypes: types,
},
this.workspace);
this.workspace.id);
});
test(

View File

@@ -130,6 +130,49 @@ export function assertEventFired(spy, instanceType, expectedProperties,
sinon.assert.calledWith(spy, expectedEvent);
}
/**
* Returns a matcher that asserts that the actual object has the same properties
* and values (shallowly equated) as the expected object.
* @param {!Object} expected The expected set of properties we expect the
* actual object to have.
* @return {function(*): boolean} A matcher that returns true if the `actual`
* object has all of the properties of the `expected` param, with the same
* values.
*/
function shallowMatch(expected) {
return (actual) => {
for (const key in expected) {
if (actual[key] !== expected[key]) {
return false;
}
}
return true;
};
}
/**
* Asserts that an event with the given values (shallowly evaluated) was fired.
* @param {!SinonSpy|!SinonSpyCall} spy The spy or spy call to use.
* @param {function(new:Blockly.Events.Abstract)} instanceType Expected instance
* type of event fired.
* @param {!Object<string, *>} expectedProperties Map of of expected properties
* to check on fired event.
* @param {string} expectedWorkspaceId Expected workspace id of event fired.
* @param {?string=} expectedBlockId Expected block id of event fired.
*/
export function assertEventFiredShallow(
spy, instanceType, expectedProperties, expectedWorkspaceId, expectedBlockId) {
const properties = {
...expectedProperties,
workspaceId: expectedWorkspaceId,
blockId: expectedBlockId,
};
sinon.assert.calledWith(
spy,
sinon.match.instanceOf(instanceType)
.and(shallowMatch(properties)));
}
/**
* Asserts that an event with the given values was not fired.
* @param {!SpyCall} spy The spy to use.