mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 09:12:52 +00:00
620 lines
25 KiB
JavaScript
620 lines
25 KiB
JavaScript
import { setTimeout } from 'node:timers/promises';
|
|
|
|
describe('iD.coreHistory', function () {
|
|
var context, history, spy;
|
|
var actionNoop = function(g) { return g; };
|
|
var actionAddNode = function (nodeID) {
|
|
return function(g) {
|
|
return g.replace(iD.osmNode({ id: nodeID }));
|
|
};
|
|
};
|
|
|
|
beforeEach(function () {
|
|
context = iD.coreContext().assetPath('../dist/').init();
|
|
history = context.history();
|
|
spy = sinon.spy();
|
|
// clear lock
|
|
iD.prefs(history._getKey('lock'), null);
|
|
});
|
|
|
|
describe('#graph', function () {
|
|
it('returns the current graph', function () {
|
|
expect(history.graph()).to.be.an.instanceOf(iD.coreGraph);
|
|
});
|
|
});
|
|
|
|
describe('#merge', function () {
|
|
it('merges the entities into all graph versions', function () {
|
|
var n = iD.osmNode({id: 'n'});
|
|
history.merge([n]);
|
|
expect(history.graph().entity('n')).to.equal(n);
|
|
});
|
|
|
|
it('emits a merge event with the new entities', function () {
|
|
var n = iD.osmNode({id: 'n'});
|
|
history.on('merge', spy);
|
|
history.merge([n]);
|
|
expect(spy).to.have.been.calledWith([n]);
|
|
});
|
|
});
|
|
|
|
describe('#perform', function () {
|
|
it('returns a difference', function () {
|
|
expect(history.perform(actionNoop).changes()).to.eql({});
|
|
});
|
|
|
|
it('updates the graph', function () {
|
|
var node = iD.osmNode();
|
|
history.perform(function (graph) { return graph.replace(node); });
|
|
expect(history.graph().entity(node.id)).to.equal(node);
|
|
});
|
|
|
|
it('pushes an undo annotation', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
expect(history.undoAnnotation()).to.equal('annotation');
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.on('change', spy);
|
|
var difference = history.perform(actionNoop);
|
|
expect(spy).to.have.been.calledWith(difference);
|
|
expect(spy.callCount).to.eql(1);
|
|
});
|
|
|
|
it('performs multiple actions', function () {
|
|
var action1 = sinon.stub().returns(iD.coreGraph());
|
|
var action2 = sinon.stub().returns(iD.coreGraph());
|
|
history.perform(action1, action2, 'annotation');
|
|
expect(action1).to.have.been.called;
|
|
expect(action2).to.have.been.called;
|
|
expect(history.undoAnnotation()).to.equal('annotation');
|
|
});
|
|
|
|
it('performs transitionable actions in a transition', async () => {
|
|
var action1 = function() { return iD.coreGraph(); };
|
|
action1.transitionable = true;
|
|
history.on('change', spy);
|
|
history.perform(action1);
|
|
await setTimeout(300);
|
|
expect(spy.callCount).to.be.above(2);
|
|
});
|
|
});
|
|
|
|
describe('#replace', function () {
|
|
it('returns a difference', function () {
|
|
expect(history.replace(actionNoop).changes()).to.eql({});
|
|
});
|
|
|
|
it('updates the graph', function () {
|
|
var node = iD.osmNode();
|
|
history.replace(function (graph) { return graph.replace(node); });
|
|
expect(history.graph().entity(node.id)).to.equal(node);
|
|
});
|
|
|
|
it('replaces the undo annotation', function () {
|
|
history.perform(actionNoop, 'annotation1');
|
|
history.replace(actionNoop, 'annotation2');
|
|
expect(history.undoAnnotation()).to.equal('annotation2');
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.on('change', spy);
|
|
var difference = history.replace(actionNoop);
|
|
expect(spy).to.have.been.calledWith(difference);
|
|
});
|
|
|
|
it('performs multiple actions', function () {
|
|
var action1 = sinon.stub().returns(iD.coreGraph());
|
|
var action2 = sinon.stub().returns(iD.coreGraph());
|
|
history.replace(action1, action2, 'annotation');
|
|
expect(action1).to.have.been.called;
|
|
expect(action2).to.have.been.called;
|
|
expect(history.undoAnnotation()).to.equal('annotation');
|
|
});
|
|
});
|
|
|
|
describe('#pop', function () {
|
|
it('returns a difference', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
expect(history.pop().changes()).to.eql({});
|
|
});
|
|
|
|
it('updates the graph', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.pop();
|
|
expect(history.undoAnnotation()).to.be.undefined;
|
|
});
|
|
|
|
it('does not push the redo stack', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.pop();
|
|
expect(history.redoAnnotation()).to.be.undefined;
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.perform(actionNoop);
|
|
history.on('change', spy);
|
|
var difference = history.pop();
|
|
expect(spy).to.have.been.calledWith(difference);
|
|
});
|
|
|
|
it('pops n times', function () {
|
|
history.perform(actionNoop, 'annotation1');
|
|
history.perform(actionNoop, 'annotation2');
|
|
history.perform(actionNoop, 'annotation3');
|
|
history.pop(2);
|
|
expect(history.undoAnnotation()).to.equal('annotation1');
|
|
});
|
|
|
|
it('pops 0 times', function () {
|
|
history.perform(actionNoop, 'annotation1');
|
|
history.perform(actionNoop, 'annotation2');
|
|
history.perform(actionNoop, 'annotation3');
|
|
history.pop(0);
|
|
expect(history.undoAnnotation()).to.equal('annotation3');
|
|
});
|
|
|
|
it('pops 1 time if argument is invalid', function () {
|
|
history.perform(actionNoop, 'annotation1');
|
|
history.perform(actionNoop, 'annotation2');
|
|
history.perform(actionNoop, 'annotation3');
|
|
history.pop('foo');
|
|
expect(history.undoAnnotation()).to.equal('annotation2');
|
|
history.pop(-1);
|
|
expect(history.undoAnnotation()).to.equal('annotation1');
|
|
});
|
|
});
|
|
|
|
describe('#overwrite', function () {
|
|
it('returns a difference', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
expect(history.overwrite(actionNoop).changes()).to.eql({});
|
|
});
|
|
|
|
it('updates the graph', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
var node = iD.osmNode();
|
|
history.overwrite(function (graph) { return graph.replace(node); });
|
|
expect(history.graph().entity(node.id)).to.equal(node);
|
|
});
|
|
|
|
it('replaces the undo annotation', function () {
|
|
history.perform(actionNoop, 'annotation1');
|
|
history.overwrite(actionNoop, 'annotation2');
|
|
expect(history.undoAnnotation()).to.equal('annotation2');
|
|
});
|
|
|
|
it('does not push the redo stack', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.overwrite(actionNoop, 'annotation2');
|
|
expect(history.redoAnnotation()).to.be.undefined;
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.on('change', spy);
|
|
var difference = history.overwrite(actionNoop, 'annotation2');
|
|
expect(spy).to.have.been.calledWith(difference);
|
|
});
|
|
|
|
it('performs multiple actions', function () {
|
|
var action1 = sinon.stub().returns(iD.coreGraph());
|
|
var action2 = sinon.stub().returns(iD.coreGraph());
|
|
history.perform(actionNoop, 'annotation');
|
|
history.overwrite(action1, action2, 'annotation2');
|
|
expect(action1).to.have.been.called;
|
|
expect(action2).to.have.been.called;
|
|
expect(history.undoAnnotation()).to.equal('annotation2');
|
|
});
|
|
});
|
|
|
|
describe('#undo', function () {
|
|
it('returns a difference', function () {
|
|
expect(history.undo().changes()).to.eql({});
|
|
});
|
|
|
|
it('pops the undo stack', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.undo();
|
|
expect(history.undoAnnotation()).to.be.undefined;
|
|
});
|
|
|
|
it('pushes the redo stack', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.undo();
|
|
expect(history.redoAnnotation()).to.equal('annotation');
|
|
});
|
|
|
|
it('emits an undone event', function () {
|
|
history.perform(actionNoop);
|
|
history.on('undone', spy);
|
|
history.undo();
|
|
expect(spy).to.have.been.called;
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.perform(actionNoop);
|
|
history.on('change', spy);
|
|
var difference = history.undo();
|
|
expect(spy).to.have.been.calledWith(difference);
|
|
});
|
|
});
|
|
|
|
describe('#redo', function () {
|
|
it('returns a difference', function () {
|
|
expect(history.redo().changes()).to.eql({});
|
|
});
|
|
|
|
it('does redo into an annotated state', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.on('redone', spy);
|
|
history.undo();
|
|
history.redo();
|
|
expect(history.undoAnnotation()).to.equal('annotation');
|
|
expect(spy).to.have.been.called;
|
|
});
|
|
|
|
it('does not redo into a non-annotated state', function () {
|
|
history.perform(actionNoop);
|
|
history.on('redone', spy);
|
|
history.undo();
|
|
history.redo();
|
|
expect(spy).not.to.have.been.called;
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.perform(actionNoop);
|
|
history.undo();
|
|
history.on('change', spy);
|
|
var difference = history.redo();
|
|
expect(spy).to.have.been.calledWith(difference);
|
|
});
|
|
});
|
|
|
|
describe('#pauseChangeDispatch / #resumeChangeDispatch', function() {
|
|
it('prevents change events from getting dispatched', function() {
|
|
history.perform(actionNoop, 'base');
|
|
history.on('change', spy);
|
|
|
|
history.pauseChangeDispatch();
|
|
|
|
history.perform(actionNoop, 'perform');
|
|
expect(spy).to.have.not.been.called;
|
|
history.replace(actionNoop, 'replace');
|
|
expect(spy).to.have.not.been.called;
|
|
history.overwrite(actionNoop, 'replace');
|
|
expect(spy).to.have.not.been.called;
|
|
history.undo();
|
|
expect(spy).to.have.not.been.called;
|
|
history.redo();
|
|
expect(spy).to.have.not.been.called;
|
|
history.pop();
|
|
expect(spy).to.have.not.been.called;
|
|
|
|
var diff = history.resumeChangeDispatch();
|
|
expect(spy).to.have.been.calledOnceWith(diff);
|
|
});
|
|
|
|
it('does nothing if resume called before pause', function() {
|
|
history.perform(actionNoop, 'base');
|
|
history.on('change', spy);
|
|
|
|
history.resumeChangeDispatch();
|
|
expect(spy).to.have.not.been.called;
|
|
});
|
|
|
|
it('uses earliest difference if pause called multiple times', function() {
|
|
history.perform(actionNoop, 'base');
|
|
history.on('change', spy);
|
|
|
|
history.pauseChangeDispatch();
|
|
history.perform(actionAddNode('a'), 'perform');
|
|
|
|
history.pauseChangeDispatch();
|
|
history.perform(actionAddNode('b'), 'perform');
|
|
|
|
var diff = history.resumeChangeDispatch();
|
|
expect(spy).to.have.been.calledOnceWith(diff);
|
|
expect(diff.changes()).to.include.keys(['a', 'b']);
|
|
});
|
|
});
|
|
|
|
describe('#changes', function () {
|
|
it('includes created entities', function () {
|
|
var node = iD.osmNode();
|
|
history.perform(function (graph) { return graph.replace(node); });
|
|
expect(history.changes().created).to.eql([node]);
|
|
});
|
|
|
|
it('includes modified entities', function () {
|
|
var node1 = iD.osmNode({id: 'n1'});
|
|
var node2 = node1.update({ tags: { yes: 'no' } });
|
|
history.merge([node1]);
|
|
history.perform(function (graph) { return graph.replace(node2); });
|
|
expect(history.changes().modified).to.eql([node2]);
|
|
});
|
|
|
|
it('includes deleted entities', function () {
|
|
var node = iD.osmNode({id: 'n1'});
|
|
history.merge([node]);
|
|
history.perform(function (graph) { return graph.remove(node); });
|
|
expect(history.changes().deleted).to.eql([node]);
|
|
});
|
|
});
|
|
|
|
describe('#hasChanges', function() {
|
|
it('is true when any of change\'s values are nonempty', function() {
|
|
var node = iD.osmNode();
|
|
history.perform(function (graph) { return graph.replace(node); });
|
|
expect(history.hasChanges()).to.eql(true);
|
|
});
|
|
|
|
it('is false when all of change\'s values are empty', function() {
|
|
expect(history.hasChanges()).to.eql(false);
|
|
});
|
|
});
|
|
|
|
describe('#reset', function () {
|
|
it('clears the version stack', function () {
|
|
history.perform(actionNoop, 'annotation');
|
|
history.perform(actionNoop, 'annotation');
|
|
history.undo();
|
|
history.reset();
|
|
expect(history.undoAnnotation()).to.be.undefined;
|
|
expect(history.redoAnnotation()).to.be.undefined;
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.on('change', spy);
|
|
history.reset();
|
|
expect(spy).to.have.been.called;
|
|
});
|
|
});
|
|
|
|
describe('#checkpoint', function () {
|
|
it('saves and resets to checkpoints', function () {
|
|
history.perform(actionNoop, 'annotation1');
|
|
history.perform(actionNoop, 'annotation2');
|
|
history.perform(actionNoop, 'annotation3');
|
|
history.checkpoint('check1');
|
|
history.perform(actionNoop, 'annotation4');
|
|
history.perform(actionNoop, 'annotation5');
|
|
history.checkpoint('check2');
|
|
history.perform(actionNoop, 'annotation6');
|
|
history.perform(actionNoop, 'annotation7');
|
|
history.perform(actionNoop, 'annotation8');
|
|
|
|
history.reset('check1');
|
|
expect(history.undoAnnotation()).to.equal('annotation3');
|
|
|
|
history.reset('check2');
|
|
expect(history.undoAnnotation()).to.equal('annotation5');
|
|
|
|
history.reset('check1');
|
|
expect(history.undoAnnotation()).to.equal('annotation3');
|
|
});
|
|
|
|
it('emits a change event', function () {
|
|
history.on('change', spy);
|
|
history.reset();
|
|
expect(spy).to.have.been.called;
|
|
});
|
|
});
|
|
|
|
describe('#toJSON', function() {
|
|
it('doesn\'t generate unsaveable changes', function() {
|
|
history.perform(actionAddNode('n-1'));
|
|
history.perform(iD.actionDeleteNode('n-1'));
|
|
expect(history.toJSON()).to.be.not.ok;
|
|
});
|
|
|
|
it('generates v3 JSON', function() {
|
|
var node_1 = iD.osmNode({id: 'n-1'});
|
|
var node1 = iD.osmNode({id: 'n1'});
|
|
var node2 = iD.osmNode({id: 'n2'});
|
|
var node3 = iD.osmNode({id: 'n3'});
|
|
history.merge([node1, node2, node3]);
|
|
history.perform(iD.actionAddEntity(node_1)); // addition
|
|
history.perform(iD.actionChangeTags('n2', {k: 'v'})); // modification
|
|
history.perform(iD.actionDeleteNode('n3')); // deletion
|
|
|
|
var json = JSON.parse(history.toJSON());
|
|
var node_1_json = JSON.parse(JSON.stringify(node_1));
|
|
var node1_json = JSON.parse(JSON.stringify(node1));
|
|
var node2_json = JSON.parse(JSON.stringify(node2));
|
|
var node2_upd_json = JSON.parse(JSON.stringify(node2.update({tags: {k: 'v'}})));
|
|
var node3_json = JSON.parse(JSON.stringify(node3));
|
|
|
|
expect(json.version).to.eql(3);
|
|
expect(json.entities).to.deep.own.include(node_1_json);
|
|
expect(json.entities).to.not.include(node1_json);
|
|
expect(json.entities).to.deep.own.include(node2_upd_json);
|
|
expect(json.entities).to.not.include(node3_json);
|
|
|
|
expect(json.baseEntities).to.not.include(node_1_json);
|
|
expect(json.baseEntities).to.not.include(node1_json);
|
|
expect(json.baseEntities).to.deep.own.include(node2_json);
|
|
expect(json.baseEntities).to.deep.own.include(node3_json);
|
|
});
|
|
});
|
|
|
|
describe('#fromJSON', function() {
|
|
it('restores from v1 JSON (creation)', function() {
|
|
var json = {
|
|
'stack': [
|
|
{'entities': {}},
|
|
{'entities': {'n-1': {'loc': [1, 2], 'id': 'n-1'}}, 'imageryUsed': ['Bing'], 'annotation': 'Added a point.'}
|
|
],
|
|
'nextIDs': {'node': -2, 'way': -1, 'relation': -1},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
expect(history.graph().entity('n-1')).to.eql(iD.osmNode({id: 'n-1', loc: [1, 2]}));
|
|
expect(history.undoAnnotation()).to.eql('Added a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -2, way: -1, relation: -1});
|
|
});
|
|
|
|
it('restores from v1 JSON (modification)', function() {
|
|
var json = {
|
|
'stack': [
|
|
{'entities': {}},
|
|
{'entities': {'n-1': {'loc': [1, 2], 'id': 'n-1'}}, 'imageryUsed': ['Bing'], 'annotation': 'Added a point.'},
|
|
{'entities': {'n-1': {'loc': [2, 3], 'id': 'n-1', 'v': 1}}, 'imageryUsed': ['Bing'], 'annotation': 'Moved a point.'}
|
|
],
|
|
'nextIDs': {'node': -2, 'way': -1, 'relation': -1},
|
|
'index': 2
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
expect(history.graph().entity('n-1')).to.eql(iD.osmNode({id: 'n-1', loc: [2, 3], v: 1}));
|
|
expect(history.undoAnnotation()).to.eql('Moved a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -2, way: -1, relation: -1});
|
|
});
|
|
|
|
it('restores from v1 JSON (deletion)', function() {
|
|
var json = {
|
|
'stack': [
|
|
{'entities': {}},
|
|
{'entities': {'n1': 'undefined'}, 'imageryUsed': ['Bing'], 'annotation': 'Deleted a point.'}
|
|
],
|
|
'nextIDs': {'node': -1, 'way': -2, 'relation': -3},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
history.merge([iD.osmNode({id: 'n1'})]);
|
|
expect(history.graph().hasEntity('n1')).to.be.undefined;
|
|
expect(history.undoAnnotation()).to.eql('Deleted a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -1, way: -2, relation: -3});
|
|
});
|
|
|
|
it('restores from v2 JSON (creation)', function() {
|
|
var json = {
|
|
'version': 2,
|
|
'entities': [
|
|
{'loc': [1, 2], 'id': 'n-1'}
|
|
],
|
|
'stack': [
|
|
{},
|
|
{'modified': ['n-1v0'], 'imageryUsed': ['Bing'], 'annotation': 'Added a point.'}
|
|
],
|
|
'nextIDs': {'node': -2, 'way': -1, 'relation': -1},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
expect(history.graph().entity('n-1')).to.eql(iD.osmNode({id: 'n-1', loc: [1, 2]}));
|
|
expect(history.undoAnnotation()).to.eql('Added a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -2, way: -1, relation: -1});
|
|
expect(history.difference().created().length).to.eql(1);
|
|
});
|
|
|
|
it('restores from v2 JSON (modification)', function() {
|
|
var json = {
|
|
'version': 2,
|
|
'entities': [
|
|
{'loc': [2, 3], 'id': 'n1', 'v': 1}
|
|
],
|
|
'stack': [
|
|
{},
|
|
{'modified': ['n1v1'], 'imageryUsed': ['Bing'], 'annotation': 'Moved a point.'}
|
|
],
|
|
'nextIDs': {'node': -2, 'way': -1, 'relation': -1},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
history.merge([iD.osmNode({id: 'n1'})]); // Shouldn't be necessary; flaw in v2 format (see #2135)
|
|
expect(history.graph().entity('n1')).to.eql(iD.osmNode({id: 'n1', loc: [2, 3], v: 1}));
|
|
expect(history.undoAnnotation()).to.eql('Moved a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -2, way: -1, relation: -1});
|
|
expect(history.difference().modified().length).to.eql(1);
|
|
});
|
|
|
|
it('restores from v2 JSON (deletion)', function() {
|
|
var json = {
|
|
'version': 2,
|
|
'entities': [],
|
|
'stack': [
|
|
{},
|
|
{'deleted': ['n1'], 'imageryUsed': ['Bing'], 'annotation': 'Deleted a point.'}
|
|
],
|
|
'nextIDs': {'node': -1, 'way': -2, 'relation': -3},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
history.merge([iD.osmNode({id: 'n1'})]); // Shouldn't be necessary; flaw in v2 format (see #2135)
|
|
expect(history.graph().hasEntity('n1')).to.be.undefined;
|
|
expect(history.undoAnnotation()).to.eql('Deleted a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -1, way: -2, relation: -3});
|
|
expect(history.difference().deleted().length).to.eql(1);
|
|
});
|
|
|
|
it('restores from v3 JSON (creation)', function() {
|
|
var json = {
|
|
'version': 3,
|
|
'entities': [
|
|
{'loc': [1, 2], 'id': 'n-1'}
|
|
],
|
|
'baseEntities': [],
|
|
'stack': [
|
|
{},
|
|
{'modified': ['n-1v0'], 'imageryUsed': ['Bing'], 'annotation': 'Added a point.'}
|
|
],
|
|
'nextIDs': {'node': -2, 'way': -1, 'relation': -1},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
expect(history.graph().entity('n-1')).to.eql(iD.osmNode({id: 'n-1', loc: [1, 2]}));
|
|
expect(history.undoAnnotation()).to.eql('Added a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -2, way: -1, relation: -1});
|
|
expect(history.difference().created().length).to.eql(1);
|
|
});
|
|
|
|
it('restores from v3 JSON (modification)', function() {
|
|
var json = {
|
|
'version': 3,
|
|
'entities': [
|
|
{'loc': [2, 3], 'id': 'n1', 'v': 1}
|
|
],
|
|
'baseEntities': [{'loc': [1, 2], 'id': 'n1'}],
|
|
'stack': [
|
|
{},
|
|
{'modified': ['n1v1'], 'imageryUsed': ['Bing'], 'annotation': 'Moved a point.'}
|
|
],
|
|
'nextIDs': {'node': -2, 'way': -1, 'relation': -1},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
expect(history.graph().entity('n1')).to.eql(iD.osmNode({id: 'n1', loc: [2, 3], v: 1}));
|
|
expect(history.undoAnnotation()).to.eql('Moved a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -2, way: -1, relation: -1});
|
|
expect(history.difference().modified().length).to.eql(1);
|
|
});
|
|
|
|
it('restores from v3 JSON (deletion)', function() {
|
|
var json = {
|
|
'version': 3,
|
|
'entities': [],
|
|
'baseEntities': [{'loc': [1, 2], 'id': 'n1'}],
|
|
'stack': [
|
|
{},
|
|
{'deleted': ['n1'], 'imageryUsed': ['Bing'], 'annotation': 'Deleted a point.'}
|
|
],
|
|
'nextIDs': {'node': -1, 'way': -2, 'relation': -3},
|
|
'index': 1
|
|
};
|
|
history.fromJSON(JSON.stringify(json));
|
|
expect(history.graph().hasEntity('n1')).to.be.undefined;
|
|
expect(history.undoAnnotation()).to.eql('Deleted a point.');
|
|
expect(history.imageryUsed()).to.eql(['Bing']);
|
|
expect(iD.osmEntity.id.next).to.eql({node: -1, way: -2, relation: -3});
|
|
expect(history.difference().deleted().length).to.eql(1);
|
|
});
|
|
});
|
|
});
|