Initial commit
Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com> Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com> Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com> Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com> Co-Authored-By: Johan <4934465+joolsus@users.noreply.github.com> Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com> Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
42
packages/noodl-editor/tests/SpecRunner.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Noodl Jasmine Spec Runner</title>
|
||||
|
||||
<link rel="shortcut icon" type="image/png" href="lib/jasmine-3.7.1/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="lib/jasmine-3.7.1/jasmine.css">
|
||||
|
||||
<!-- libs needed for some of the views -->
|
||||
<script type="text/javascript" src="../src/assets/lib/jquery-min.js"></script>
|
||||
<script type="text/javascript" src="../src/assets/lib/jquery.autosize.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var fs = require('fs');
|
||||
['.html', '.css'].forEach(ext => {
|
||||
require.extensions[ext] = function (module, filename) {
|
||||
module.exports = fs.readFileSync(filename, 'utf8');
|
||||
};
|
||||
});
|
||||
require.extensions['.json'] = function (module, filename) {
|
||||
module.exports = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
||||
};
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="lib/jasmine-3.7.1/jasmine.js"></script>
|
||||
<script type="text/javascript" src="lib/jasmine-3.7.1/jasmine-html.js"></script>
|
||||
<script type="text/javascript" src="lib/jasmine-3.7.1/boot.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60 * 1000;
|
||||
</script>
|
||||
|
||||
<script defer type="text/javascript" src="http://localhost:8081/index.bundle.js" onload="document.querySelector('#loader').remove()"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="loader">Waiting for webpack...</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
390
packages/noodl-editor/tests/cloud/cloudformation.js
Normal file
@@ -0,0 +1,390 @@
|
||||
const CloudFormation = require('@noodl-utils/cloudformation').default;
|
||||
const SchemaModel = require('@noodl-models/schemamodel');
|
||||
const _ = require('lodash');
|
||||
const { _listenersEnabled } = require('../../src/shared/model');
|
||||
|
||||
// Noodl unit tests cloud services
|
||||
const cs = {
|
||||
endpoint: 'https://cs2.noodlapp.com/noodl-dev/w6lw4bfbzp',
|
||||
appId: 'noodl-dev-w6lw4bfbzp',
|
||||
masterKey: 'yl3QiFnutSUjTR4D'
|
||||
};
|
||||
|
||||
function _makeRequest(path, options) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
var json;
|
||||
try {
|
||||
json = JSON.parse(xhr.response);
|
||||
} catch (e) {}
|
||||
|
||||
if (xhr.status === 200 || xhr.status === 201) {
|
||||
options.success(json);
|
||||
} else {
|
||||
options.error(json);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open(options.method || 'GET', cs.endpoint + path, true);
|
||||
|
||||
xhr.setRequestHeader('X-Parse-Application-Id', cs.appId);
|
||||
xhr.setRequestHeader('X-Parse-MASTER-Key', cs.masterKey);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
|
||||
xhr.send(JSON.stringify(options.content));
|
||||
}
|
||||
|
||||
function deleteCollection(options) {
|
||||
// First delete all objects
|
||||
_makeRequest('/classes/' + options.collection, {
|
||||
method: 'GET',
|
||||
success: (r) => {
|
||||
const url = new URL(cs.endpoint);
|
||||
|
||||
const _batchDelete = {
|
||||
requests: r.results.map((o) => ({
|
||||
method: 'DELETE',
|
||||
path: url.pathname + '/classes/' + options.collection + '/' + o.objectId
|
||||
}))
|
||||
};
|
||||
|
||||
_makeRequest('/batch', {
|
||||
method: 'POST',
|
||||
content: _batchDelete,
|
||||
success: function (response) {
|
||||
// Collection empty, delete schema
|
||||
_makeRequest('/schemas/' + options.collection, {
|
||||
method: 'DELETE',
|
||||
success: function (response) {
|
||||
options.success();
|
||||
},
|
||||
error: function (res) {
|
||||
console.log(res.error);
|
||||
options.error();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: (res) => {
|
||||
console.log(res.error);
|
||||
options.error();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: (err) => {
|
||||
console.log(err);
|
||||
options.error();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _pluck(o, fields) {
|
||||
var _o = {};
|
||||
fields.forEach((f) => {
|
||||
_o[f] = o[f];
|
||||
});
|
||||
return _o;
|
||||
}
|
||||
|
||||
function verifyObjects(options) {
|
||||
_makeRequest('/classes/' + options.collection, {
|
||||
method: 'GET',
|
||||
success: (r) => {
|
||||
if (options.data.length !== r.results.length) options.error();
|
||||
else {
|
||||
const a = {},
|
||||
b = {};
|
||||
options.data.forEach((o) => {
|
||||
a[o.ref] = _pluck(o, options.fields);
|
||||
});
|
||||
r.results.forEach((o) => {
|
||||
b[o.ref] = _pluck(o, options.fields);
|
||||
});
|
||||
|
||||
if (_.isEqual(a, b)) options.success();
|
||||
else options.error();
|
||||
}
|
||||
},
|
||||
error: (err) => {
|
||||
console.log(res.error);
|
||||
options.error();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifySchema(options) {
|
||||
var sm = new SchemaModel(cs);
|
||||
sm.getSchema({
|
||||
collection: options.name,
|
||||
success: function (schema) {
|
||||
for (var key in options.fields) {
|
||||
if (schema.fields[key] === undefined || schema.fields[key].type !== options.fields[key].type) {
|
||||
return options.result(false);
|
||||
}
|
||||
}
|
||||
|
||||
options.result(true);
|
||||
},
|
||||
error: function () {
|
||||
options.result(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe('Cloud formation', function () {
|
||||
beforeEach(function (done) {
|
||||
deleteCollection({
|
||||
collection: 'form_test',
|
||||
success: function () {
|
||||
done();
|
||||
},
|
||||
error: function () {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
xit('can handle create collection', function (done) {
|
||||
const cf = new CloudFormation({
|
||||
cs: cs
|
||||
});
|
||||
|
||||
const formationJson = {
|
||||
formation: [
|
||||
{
|
||||
type: 'collection',
|
||||
name: 'form_test',
|
||||
properties: {
|
||||
a: {
|
||||
type: 'Number'
|
||||
},
|
||||
b: {
|
||||
type: 'String'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
cf._form({
|
||||
template: formationJson,
|
||||
success: function () {
|
||||
verifySchema({
|
||||
name: 'form_test',
|
||||
fields: {
|
||||
a: {
|
||||
type: 'Number'
|
||||
},
|
||||
b: {
|
||||
type: 'String'
|
||||
}
|
||||
},
|
||||
result: function (r) {
|
||||
expect(r).toBe(true);
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function () {}
|
||||
});
|
||||
});
|
||||
|
||||
xit('will add property to existing collection', function (done) {
|
||||
const cf = new CloudFormation({
|
||||
cs: cs
|
||||
});
|
||||
|
||||
const formationJson1 = {
|
||||
formation: [
|
||||
{
|
||||
type: 'collection',
|
||||
name: 'form_test',
|
||||
properties: {
|
||||
a: {
|
||||
type: 'Number'
|
||||
},
|
||||
b: {
|
||||
type: 'String'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const formationJson2 = {
|
||||
formation: [
|
||||
{
|
||||
type: 'collection',
|
||||
name: 'form_test',
|
||||
properties: {
|
||||
c: {
|
||||
type: 'Date'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
cf._form({
|
||||
template: formationJson1,
|
||||
success: function () {
|
||||
cf._form({
|
||||
template: formationJson2,
|
||||
success: function () {
|
||||
verifySchema({
|
||||
name: 'form_test',
|
||||
fields: {
|
||||
a: {
|
||||
type: 'Number'
|
||||
},
|
||||
b: {
|
||||
type: 'String'
|
||||
},
|
||||
c: {
|
||||
type: 'Date'
|
||||
}
|
||||
},
|
||||
result: function (r) {
|
||||
expect(r).toBe(true);
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
expect(true).toBe(false); // Fail
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
expect(true).toBe(false); // Fail
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
xit('will fail with property clash', function (done) {
|
||||
const cf = new CloudFormation({
|
||||
cs: cs
|
||||
});
|
||||
|
||||
const formationJson1 = {
|
||||
formation: [
|
||||
{
|
||||
type: 'collection',
|
||||
name: 'form_test',
|
||||
properties: {
|
||||
a: {
|
||||
type: 'Number'
|
||||
},
|
||||
b: {
|
||||
type: 'String'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const formationJson2 = {
|
||||
formation: [
|
||||
{
|
||||
type: 'collection',
|
||||
name: 'form_test',
|
||||
properties: {
|
||||
a: {
|
||||
type: 'String'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
cf._form({
|
||||
template: formationJson1,
|
||||
success: function () {
|
||||
cf._form({
|
||||
template: formationJson2,
|
||||
success: function () {
|
||||
expect(true).toBe(false); // Fail
|
||||
done();
|
||||
},
|
||||
error: function (err) {
|
||||
expect(err).toBe('Property already exists with different type a for collection form_test');
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function () {
|
||||
expect(true).toBe(false); // Fail
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
xit('can create sample data', function (done) {
|
||||
const cf = new CloudFormation({
|
||||
cs: cs
|
||||
});
|
||||
|
||||
const data = [
|
||||
{
|
||||
b: 20,
|
||||
a: '1',
|
||||
ref: 'A'
|
||||
},
|
||||
{
|
||||
b: 22,
|
||||
a: '2',
|
||||
ref: 'B'
|
||||
},
|
||||
{
|
||||
b: 25,
|
||||
a: '3',
|
||||
ref: 'C'
|
||||
}
|
||||
];
|
||||
|
||||
const formationJson = {
|
||||
formation: [
|
||||
{
|
||||
type: 'collection',
|
||||
name: 'form_test',
|
||||
properties: {
|
||||
a: {
|
||||
type: 'String'
|
||||
},
|
||||
b: {
|
||||
type: 'Number'
|
||||
}
|
||||
},
|
||||
data: data
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
cf._form({
|
||||
template: formationJson,
|
||||
success: function () {
|
||||
verifyObjects({
|
||||
collection: 'form_test',
|
||||
data: data,
|
||||
fields: ['a', 'b'],
|
||||
success: () => {
|
||||
expect(true).toBe(true);
|
||||
done();
|
||||
},
|
||||
error: () => {
|
||||
expect(true).toBe(false); // Fail
|
||||
done();
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function (err) {
|
||||
expect(true).toBe(false); // Fail
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
1
packages/noodl-editor/tests/cloud/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './cloudformation';
|
||||
372
packages/noodl-editor/tests/components/componentconnections.js
Normal file
@@ -0,0 +1,372 @@
|
||||
const NodeGraphModel = require('@noodl-models/nodegraphmodel').NodeGraphModel;
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
const { ComponentModel } = require('@noodl-models/componentmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('Connecting component inputs and outputs', function () {
|
||||
var g1, c1;
|
||||
var ci, co, n1, n2, co2;
|
||||
var p;
|
||||
var con1, con2;
|
||||
|
||||
beforeEach(() => {
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
|
||||
g1 = new NodeGraphModel();
|
||||
|
||||
c1 = new ComponentModel({
|
||||
name: 'c1',
|
||||
graph: g1
|
||||
});
|
||||
|
||||
ci = NodeGraphNode.fromJSON({
|
||||
type: 'Component Inputs',
|
||||
id: 'A'
|
||||
});
|
||||
g1.addRoot(ci);
|
||||
|
||||
co = NodeGraphNode.fromJSON({
|
||||
type: 'Component Outputs',
|
||||
id: 'B'
|
||||
});
|
||||
g1.addRoot(co);
|
||||
|
||||
co2 = NodeGraphNode.fromJSON({
|
||||
type: 'Component Outputs',
|
||||
id: 'B2'
|
||||
});
|
||||
g1.addRoot(co2);
|
||||
|
||||
n1 = NodeGraphNode.fromJSON({
|
||||
type: 'group',
|
||||
id: 'C'
|
||||
});
|
||||
g1.addRoot(n1);
|
||||
|
||||
n2 = NodeGraphNode.fromJSON({
|
||||
type: 'group',
|
||||
id: 'D'
|
||||
});
|
||||
g1.addRoot(n2);
|
||||
|
||||
p = new ProjectModel({
|
||||
name: 'test'
|
||||
});
|
||||
p.addComponent(c1);
|
||||
|
||||
NodeLibrary.instance.registerModule(p);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
NodeLibrary.instance.unregisterModule(p);
|
||||
});
|
||||
|
||||
function addPorts() {
|
||||
c1.graph.findNodeWithId('B').addPort({
|
||||
name: 'p1',
|
||||
plug: 'input',
|
||||
type: '*',
|
||||
index: 0
|
||||
});
|
||||
|
||||
c1.graph.findNodeWithId('B').addPort({
|
||||
name: 'p2',
|
||||
plug: 'input',
|
||||
type: '*',
|
||||
index: 1
|
||||
});
|
||||
|
||||
c1.graph.findNodeWithId('A').addPort({
|
||||
name: 'p3',
|
||||
plug: 'output',
|
||||
type: '*',
|
||||
index: 2
|
||||
});
|
||||
|
||||
c1.graph.findNodeWithId('B2').addPort({
|
||||
name: 'p1',
|
||||
plug: 'input',
|
||||
type: '*',
|
||||
index: 0
|
||||
});
|
||||
}
|
||||
|
||||
function addConnections() {
|
||||
con1 = {
|
||||
fromId: n1.id,
|
||||
fromProperty: 'width',
|
||||
toId: co.id,
|
||||
toProperty: 'p1'
|
||||
};
|
||||
g1.addConnection(con1);
|
||||
|
||||
con2 = {
|
||||
fromId: ci.id,
|
||||
fromProperty: 'p3',
|
||||
toId: n1.id,
|
||||
toProperty: 'x'
|
||||
};
|
||||
g1.addConnection(con2);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
it('can add input ports to the component', function () {
|
||||
addPorts();
|
||||
|
||||
var ports = c1.getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
expect(ports[0].name).toBe('p1');
|
||||
expect(ports[0].plug).toBe('output');
|
||||
expect(ports[0].type).toBe('*');
|
||||
expect(ports[1].name).toBe('p2');
|
||||
expect(ports[1].plug).toBe('output');
|
||||
expect(ports[1].type).toBe('*');
|
||||
expect(ports[2].name).toBe('p3');
|
||||
expect(ports[2].plug).toBe('input');
|
||||
expect(ports[2].type).toBe('*');
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
it('can list ports correctly for component input/outputs', function () {
|
||||
addPorts();
|
||||
|
||||
var ports = c1.graph.findNodeWithId('B').getPorts('input');
|
||||
|
||||
expect(ports[0].name).toBe('p1');
|
||||
expect(ports[1].name).toBe('p2');
|
||||
expect(ports[0].plug).toBe('input');
|
||||
expect(ports[1].plug).toBe('input');
|
||||
expect(ports[0].type).toBe('*');
|
||||
expect(ports[1].type).toBe('*');
|
||||
expect(ports.length).toBe(2);
|
||||
|
||||
var ports = c1.graph.findNodeWithId('A').getPorts('output');
|
||||
expect(ports[0].name).toBe('p3');
|
||||
expect(ports[0].plug).toBe('output');
|
||||
expect(ports[0].type).toBe('*');
|
||||
expect(ports.length).toBe(1);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
it('reports connection status properly', function () {
|
||||
addPorts();
|
||||
|
||||
// component input
|
||||
var status = g1.getConnectionStatus({
|
||||
sourceNode: ci,
|
||||
sourcePort: 'p1',
|
||||
targetNode: n1,
|
||||
targetPort: 'width'
|
||||
});
|
||||
expect(status.connectable).toBe(true);
|
||||
|
||||
// number to number
|
||||
var status = g1.getConnectionStatus({
|
||||
sourceNode: n1,
|
||||
sourcePort: 'screenX',
|
||||
targetNode: n2,
|
||||
targetPort: 'width'
|
||||
});
|
||||
expect(status.connectable).toBe(true);
|
||||
|
||||
// component outputs
|
||||
var status = g1.getConnectionStatus({
|
||||
sourceNode: n1,
|
||||
sourcePort: 'width',
|
||||
targetNode: co,
|
||||
targetPort: 'p1'
|
||||
});
|
||||
expect(status.connectable).toBe(true);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
it('can rename ports', function () {
|
||||
addPorts();
|
||||
addConnections();
|
||||
|
||||
expect(c1.graph.findNodeWithId('B').renamePortWithName('p1', 'p2')).toBe(false);
|
||||
expect(c1.graph.findNodeWithId('B').renamePortWithName('p1', 'p1b')).toBe(true);
|
||||
expect(c1.graph.findNodeWithId('A').renamePortWithName('p3', 'p3b')).toBe(true);
|
||||
|
||||
expect(con2.fromProperty).toBe('p3b');
|
||||
expect(con1.toProperty).toBe('p1b');
|
||||
|
||||
expect(c1.graph.findNodeWithId('B').renamePortWithName('p1b', 'p1')).toBe(true);
|
||||
expect(c1.graph.findNodeWithId('A').renamePortWithName('p3b', 'p3')).toBe(true);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
it('cannot remove ports with connections', function () {
|
||||
addPorts();
|
||||
addConnections();
|
||||
|
||||
expect(c1.graph.findNodeWithId('B').removePortWithName('p1')).toBe(false);
|
||||
expect(c1.graph.findNodeWithId('B').removePortWithName('p2')).toBe(true);
|
||||
expect(c1.graph.findNodeWithId('A').removePortWithName('p3')).toBe(false);
|
||||
|
||||
expect(c1.findPortWithName('p2')).toBe(undefined);
|
||||
expect(c1.findPortWithName('p1').name).toBe('p1');
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
it('can add more connections are report type correctly', function () {
|
||||
addPorts();
|
||||
addConnections();
|
||||
|
||||
g1.removeConnection(con1);
|
||||
g1.removeConnection(con2);
|
||||
|
||||
// Single type, should just be number
|
||||
g1.addConnection({
|
||||
fromId: n1.id,
|
||||
fromProperty: 'screenX',
|
||||
toId: co2.id,
|
||||
toProperty: 'p1'
|
||||
});
|
||||
|
||||
expect(NodeLibrary.nameForPortType(c1.findPortWithName('p1').type)).toBe('number');
|
||||
|
||||
// Connect a number and boolean to the components outputs, but on different
|
||||
// nodes
|
||||
g1.addConnection({
|
||||
fromId: n1.id,
|
||||
fromProperty: 'clipOut',
|
||||
toId: co.id,
|
||||
toProperty: 'p1'
|
||||
});
|
||||
|
||||
// Resulting type should be boolean (the only type that can be converted to from both boolean and number)
|
||||
expect(NodeLibrary.nameForPortType(c1.findPortWithName('p1').type)).toBe('boolean');
|
||||
|
||||
// Adding a connection to a star type should not affect the resulting type
|
||||
g1.addConnection({
|
||||
fromId: ci.id,
|
||||
fromProperty: 'p3',
|
||||
toId: co2.id,
|
||||
toProperty: 'p1'
|
||||
});
|
||||
|
||||
expect(NodeLibrary.nameForPortType(c1.findPortWithName('p1').type)).toBe('boolean');
|
||||
|
||||
// Adding a reference type connection will cause it to break down, no type can be found
|
||||
g1.addConnection({
|
||||
fromId: n1.id,
|
||||
fromProperty: 'this',
|
||||
toId: co2.id,
|
||||
toProperty: 'p1'
|
||||
});
|
||||
|
||||
expect(c1.findPortWithName('p1').type).toBe('*');
|
||||
});
|
||||
|
||||
it('can report plug correctly', function () {
|
||||
addPorts();
|
||||
|
||||
expect(c1.findPortWithName('p1').plug).toBe('output');
|
||||
expect(c1.findPortWithName('p3').plug).toBe('input');
|
||||
|
||||
// Adding an extra port of mixed type for p1 should change the plug
|
||||
c1.graph.findNodeWithId('A').addPort({
|
||||
name: 'p1',
|
||||
plug: 'output',
|
||||
type: '*'
|
||||
});
|
||||
|
||||
expect(c1.getPorts().length).toBe(4);
|
||||
expect(c1.getPorts()).toContain({
|
||||
name: 'p1',
|
||||
type: '*',
|
||||
default: undefined,
|
||||
group: undefined,
|
||||
plug: 'output',
|
||||
index: 0
|
||||
});
|
||||
expect(c1.getPorts()).toContain({
|
||||
name: 'p1',
|
||||
type: '*',
|
||||
default: undefined,
|
||||
group: undefined,
|
||||
plug: 'input',
|
||||
index: 1
|
||||
});
|
||||
});
|
||||
|
||||
it('can ignore * types', function () {
|
||||
addPorts();
|
||||
addConnections();
|
||||
|
||||
// Remove all connections
|
||||
while (g1.connections.length > 0) {
|
||||
g1.removeConnection(g1.connections[0]);
|
||||
}
|
||||
|
||||
// Number type
|
||||
g1.addConnection({
|
||||
fromId: n1.id,
|
||||
fromProperty: 'screenX',
|
||||
toId: co.id,
|
||||
toProperty: 'p1'
|
||||
});
|
||||
|
||||
expect(c1.findPortWithName('p1').type).toBe('number');
|
||||
|
||||
// Add a connection to a * type
|
||||
g1.addConnection({
|
||||
fromId: ci.id,
|
||||
fromProperty: 'p3',
|
||||
toId: co.id,
|
||||
toProperty: 'p1'
|
||||
});
|
||||
|
||||
// Should just ignore * type and still be number
|
||||
expect(c1.findPortWithName('p1').type).toBe('number');
|
||||
});
|
||||
|
||||
it('can support units with default in types', function () {
|
||||
addPorts();
|
||||
addConnections();
|
||||
|
||||
// Remove all connections
|
||||
while (g1.connections.length > 0) {
|
||||
g1.removeConnection(g1.connections[0]);
|
||||
}
|
||||
|
||||
// Add a connection to a type with units
|
||||
g1.addConnection({
|
||||
fromId: ci.id,
|
||||
fromProperty: 'p3',
|
||||
toId: n1.id,
|
||||
toProperty: 'x'
|
||||
});
|
||||
|
||||
// Should just ignore * type and still be number
|
||||
expect(c1.findPortWithName('p3').type.name).toBe('number');
|
||||
expect(c1.findPortWithName('p3').type.units).toEqual(['px', '%']);
|
||||
expect(c1.findPortWithName('p3').default).toEqual({
|
||||
value: 10,
|
||||
unit: '%'
|
||||
});
|
||||
|
||||
expect(c1.findPortWithName('p3').group).toBe('test'); // Should inherit from connected port
|
||||
|
||||
//Change parameter value should propagate to default
|
||||
n1.setParameter('x', {
|
||||
value: 50,
|
||||
unit: 'px'
|
||||
});
|
||||
expect(c1.findPortWithName('p3').default).toEqual({
|
||||
value: 50,
|
||||
unit: 'px'
|
||||
});
|
||||
});
|
||||
|
||||
it('can rearrange ports', function () {
|
||||
addPorts();
|
||||
addConnections();
|
||||
|
||||
ci.arrangePort('p3', undefined, 'G1');
|
||||
expect(c1.findPortWithName('p3').group).toBe('G1');
|
||||
});
|
||||
});
|
||||
322
packages/noodl-editor/tests/components/componentinstances.js
Normal file
@@ -0,0 +1,322 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const NodeGraphModel = require('@noodl-models/nodegraphmodel').NodeGraphModel;
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
|
||||
describe('Component instances', function () {
|
||||
var c1, c2;
|
||||
var p, p2;
|
||||
var w;
|
||||
|
||||
beforeEach(() => {
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
|
||||
p = ProjectModel.fromJSON(project);
|
||||
NodeLibrary.instance.registerModule(p);
|
||||
|
||||
c1 = p.getComponentWithName('test');
|
||||
c2 = p.getComponentWithName('Root');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
NodeLibrary.instance.unregisterModule(p);
|
||||
});
|
||||
|
||||
it('can load project', function () {
|
||||
expect(p).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can rename component inputs and outputs', function () {
|
||||
expect(c1.graph.findNodeWithId('46a72429-263c-2ad1-3ada-ce8a98b27308').renamePortWithName('p1', 'p1b')).toBe(true);
|
||||
expect(c1.graph.findNodeWithId('c01d18bc-b8cd-e792-6fd8-89694ef8da48').renamePortWithName('p3', 'p3b')).toBe(true);
|
||||
|
||||
expect(c2.graph.connections[0].toProperty).toBe('p1b');
|
||||
expect(c2.graph.connections[1].fromProperty).toBe('p3b');
|
||||
|
||||
expect(c2.graph.findNodeWithId('56b67ac1-224e-c3c8-b058-6fee9c590bee').parameters['p1b']).toBe(50);
|
||||
expect(c2.graph.findNodeWithId('56b67ac1-224e-c3c8-b058-6fee9c590bee').parameters['p1']).toBe(undefined);
|
||||
});
|
||||
|
||||
xit('can detect unhealthy connections', function () {
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
expect(
|
||||
c2.graph.getConnectionHealth({
|
||||
sourceId: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
sourcePort: 'p3',
|
||||
targetId: 'c0210ab9-94ab-c4c8-313b-3b394d5361f6',
|
||||
targetPort: 'opacity'
|
||||
}).healthy
|
||||
).toBe(true);
|
||||
|
||||
// Remove p3 connection
|
||||
c1.graph.removeConnection(c1.graph.connections[2]);
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
expect(
|
||||
c2.graph.getConnectionHealth({
|
||||
sourceId: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
sourcePort: 'p3b',
|
||||
targetId: 'c0210ab9-94ab-c4c8-313b-3b394d5361f6',
|
||||
targetPort: 'opacity'
|
||||
}).healthy
|
||||
).toBe(false);
|
||||
|
||||
// Connect p3 to a port of different type
|
||||
c1.graph.addConnection({
|
||||
fromId: 'f89b4fcd-5cfe-c47e-7fab-03948aad878c',
|
||||
fromProperty: 'this',
|
||||
toId: 'c01d18bc-b8cd-e792-6fd8-89694ef8da48',
|
||||
toProperty: 'p3b'
|
||||
});
|
||||
|
||||
// Health should still be bad (wrong type)
|
||||
expect(
|
||||
c2.graph.getConnectionHealth({
|
||||
sourceId: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
sourcePort: 'p3b',
|
||||
targetId: 'c0210ab9-94ab-c4c8-313b-3b394d5361f6',
|
||||
targetPort: 'opacity'
|
||||
}).healthy
|
||||
).toBe(false);
|
||||
|
||||
// Remove and restore
|
||||
c1.graph.removeConnection(c1.graph.connections[2]);
|
||||
c1.graph.addConnection({
|
||||
fromId: 'f89b4fcd-5cfe-c47e-7fab-03948aad878c',
|
||||
fromProperty: 'screenY',
|
||||
toId: 'c01d18bc-b8cd-e792-6fd8-89694ef8da48',
|
||||
toProperty: 'p3b'
|
||||
});
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
// Health should be back up
|
||||
expect(
|
||||
c2.graph.getConnectionHealth({
|
||||
sourceId: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
sourcePort: 'p3b',
|
||||
targetId: 'c0210ab9-94ab-c4c8-313b-3b394d5361f6',
|
||||
targetPort: 'opacity'
|
||||
}).healthy
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('can detect unhealthy nodes', function () {
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
// Multiple roots with same category is OK
|
||||
var n = c2.graph.findNodeWithId('56b67ac1-224e-c3c8-b058-6fee9c590bee');
|
||||
expect(n.getHealth().healthy).toBe(true);
|
||||
|
||||
c2.graph.removeNode(c2.graph.findNodeWithId('97720c17-1ff1-f4b0-8f97-8d70cf795348'));
|
||||
c2.graph.removeNode(c2.graph.findNodeWithId('c0210ab9-94ab-c4c8-313b-3b394d5361f6'));
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
expect(n.getHealth().healthy).toBe(true);
|
||||
|
||||
// The component cannot have visual children
|
||||
var nn = NodeGraphNode.fromJSON({
|
||||
type: 'group',
|
||||
id: 'A'
|
||||
});
|
||||
n.addChild(nn);
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
expect(n.getHealth().healthy).toBe(false);
|
||||
|
||||
// Adding a component children node will do it
|
||||
c1.graph.findNodeWithId('f89b4fcd-5cfe-c47e-7fab-03948aad878c').addChild(
|
||||
NodeGraphNode.fromJSON({
|
||||
type: 'Component Children',
|
||||
id: 'CC'
|
||||
})
|
||||
);
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
expect(n.getHealth().healthy).toBe(true);
|
||||
|
||||
// Remove the visual root of the test component, health will become false again
|
||||
c1.graph.removeNode(c1.graph.findNodeWithId('f89b4fcd-5cfe-c47e-7fab-03948aad878c'));
|
||||
c2.graph.evaluateHealth();
|
||||
|
||||
expect(n.getHealth().healthy).toBe(false);
|
||||
});
|
||||
|
||||
xit('component renamed are propageted to component references', function () {
|
||||
var c3 = p.getComponentWithName('/has_comp_ref');
|
||||
var c4 = p.getComponentWithName('/to_be_renamed');
|
||||
|
||||
var n = c3.graph.findNodeWithId('has_comp_ref_group');
|
||||
expect(n.parameters['compref']).toBe('/to_be_renamed');
|
||||
|
||||
c4.rename('/is_renamed');
|
||||
expect(n.parameters['compref']).toBe('/is_renamed');
|
||||
});
|
||||
|
||||
var project = {
|
||||
name: 'proj1',
|
||||
components: [
|
||||
{
|
||||
name: 'outside',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'AABB',
|
||||
type: 'Component Inputs',
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'p1',
|
||||
plug: 'output',
|
||||
type: '='
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Root',
|
||||
ports: [],
|
||||
graph: {
|
||||
connections: [
|
||||
{
|
||||
fromId: '97720c17-1ff1-f4b0-8f97-8d70cf795348',
|
||||
fromProperty: 'screenX',
|
||||
toId: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
toProperty: 'p1'
|
||||
},
|
||||
{
|
||||
fromId: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
fromProperty: 'p3',
|
||||
toId: 'c0210ab9-94ab-c4c8-313b-3b394d5361f6',
|
||||
toProperty: 'opacity'
|
||||
}
|
||||
],
|
||||
roots: [
|
||||
{
|
||||
id: '97720c17-1ff1-f4b0-8f97-8d70cf795348',
|
||||
type: 'group',
|
||||
x: 359,
|
||||
y: 74,
|
||||
parameters: {},
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'c0210ab9-94ab-c4c8-313b-3b394d5361f6',
|
||||
type: 'group',
|
||||
x: 457,
|
||||
y: 276,
|
||||
parameters: {},
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: '56b67ac1-224e-c3c8-b058-6fee9c590bee',
|
||||
type: 'test',
|
||||
x: 430,
|
||||
y: 181,
|
||||
parameters: {
|
||||
p1: 50
|
||||
},
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'test',
|
||||
graph: {
|
||||
connections: [
|
||||
{
|
||||
fromId: '46a72429-263c-2ad1-3ada-ce8a98b27308',
|
||||
fromProperty: 'p2',
|
||||
toId: 'f89b4fcd-5cfe-c47e-7fab-03948aad878c',
|
||||
toProperty: 'clip'
|
||||
},
|
||||
{
|
||||
fromId: '46a72429-263c-2ad1-3ada-ce8a98b27308',
|
||||
fromProperty: 'p1',
|
||||
toId: 'f89b4fcd-5cfe-c47e-7fab-03948aad878c',
|
||||
toProperty: 'scaleX'
|
||||
},
|
||||
{
|
||||
fromId: 'f89b4fcd-5cfe-c47e-7fab-03948aad878c',
|
||||
fromProperty: 'screenX',
|
||||
toId: 'c01d18bc-b8cd-e792-6fd8-89694ef8da48',
|
||||
toProperty: 'p3'
|
||||
}
|
||||
],
|
||||
roots: [
|
||||
{
|
||||
id: '46a72429-263c-2ad1-3ada-ce8a98b27308',
|
||||
type: 'Component Inputs',
|
||||
x: 336,
|
||||
y: 115,
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'p1',
|
||||
plug: 'output',
|
||||
type: '='
|
||||
},
|
||||
{
|
||||
name: 'p2',
|
||||
plug: 'output',
|
||||
type: '='
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'f89b4fcd-5cfe-c47e-7fab-03948aad878c',
|
||||
type: 'group',
|
||||
x: 497,
|
||||
y: 211,
|
||||
parameters: {},
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'c01d18bc-b8cd-e792-6fd8-89694ef8da48',
|
||||
type: 'Component Outputs',
|
||||
x: 646,
|
||||
y: 283,
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'p3',
|
||||
plug: 'input',
|
||||
type: '='
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Test component references
|
||||
{
|
||||
name: '/has_comp_ref',
|
||||
ports: [],
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'has_comp_ref_group',
|
||||
type: 'group',
|
||||
parameters: {
|
||||
compref: '/to_be_renamed'
|
||||
},
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/to_be_renamed',
|
||||
graph: {}
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
147
packages/noodl-editor/tests/components/componentports.js
Normal file
@@ -0,0 +1,147 @@
|
||||
const { ComponentPorts } = require('@noodl-views/panels/componentports');
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const { UndoQueue } = require('@noodl-models/undo-queue-model');
|
||||
|
||||
describe('Components ports panel unit tests', function () {
|
||||
var cp, c;
|
||||
|
||||
beforeEach(() => {
|
||||
var project = {
|
||||
components: [
|
||||
{
|
||||
name: 'Root',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'Component Inputs',
|
||||
id: 'A'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
|
||||
ProjectModel.instance = ProjectModel.fromJSON(project);
|
||||
// NodeLibrary.instance.registerModule(project);
|
||||
|
||||
c = ProjectModel.instance.getComponentWithName('Root');
|
||||
cp = new ComponentPorts({
|
||||
model: c.graph.findNodeWithId('A'),
|
||||
plug: 'input'
|
||||
});
|
||||
cp.render();
|
||||
|
||||
cp.canArrangeInGroups = true; // Enable arrange in groups
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
ProjectModel.instance = undefined;
|
||||
});
|
||||
|
||||
it('can add ports', function () {
|
||||
expect(cp.performAdd('test').success).toBe(true);
|
||||
expect(c.findPortWithName('test')).not.toBe(undefined);
|
||||
|
||||
// Cannot create with same name
|
||||
expect(cp.performAdd('test').success).toBe(false);
|
||||
|
||||
// Can add with different name
|
||||
expect(cp.performAdd('test2').success).toBe(true);
|
||||
expect(c.findPortWithName('test2')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can undo add ports', function () {
|
||||
expect(cp.performAdd('undome').success).toBe(true);
|
||||
expect(c.findPortWithName('undome')).not.toBe(undefined);
|
||||
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(c.findPortWithName('undome')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('can rename+undo ports', function () {
|
||||
cp.performAdd('test');
|
||||
cp.performAdd('test2');
|
||||
|
||||
// cannot rename to existing name
|
||||
expect(
|
||||
cp.performRename({
|
||||
oldName: 'test',
|
||||
newName: 'test2'
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
cp.performRename({
|
||||
oldName: 'test',
|
||||
newName: 'test3'
|
||||
}).success
|
||||
).toBe(true);
|
||||
expect(c.findPortWithName('test3')).not.toBe(undefined);
|
||||
expect(c.findPortWithName('test')).toBe(undefined);
|
||||
|
||||
// Undo rename
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(c.findPortWithName('test3')).toBe(undefined);
|
||||
expect(c.findPortWithName('test')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can delete+undo ports', function () {
|
||||
cp.performAdd('test');
|
||||
cp.renderPorts(true);
|
||||
|
||||
expect(cp.performDelete('test').success).toBe(true);
|
||||
expect(c.findPortWithName('test')).toBe(undefined);
|
||||
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(c.findPortWithName('test')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can add group and port', function () {
|
||||
expect(cp.performAddGroup('G1').success).toBe(true);
|
||||
expect(cp.performAdd('P1').success).toBe(true);
|
||||
cp.renderPorts(true);
|
||||
|
||||
expect(c.findPortWithName('P1').group).toBe('G1');
|
||||
});
|
||||
|
||||
it('can rename group', function () {
|
||||
cp.performAddGroup('G1');
|
||||
cp.performAdd('P1');
|
||||
cp.renderPorts(true);
|
||||
|
||||
expect(
|
||||
cp.performRenameGroup({
|
||||
newName: 'G2',
|
||||
item: cp.findGroupWithName('G1')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(c.findPortWithName('P1').group).toBe('G2');
|
||||
});
|
||||
|
||||
it('cannot add group with unqualified name', function () {
|
||||
cp.performAddGroup('G2');
|
||||
cp.performAdd('P1');
|
||||
cp.renderPorts(true);
|
||||
|
||||
expect(cp.performAddGroup('G2').success).toBe(false); // Existing group
|
||||
expect(cp.performAddGroup('').success).toBe(false); // Empty name
|
||||
});
|
||||
|
||||
it('can delete group', function () {
|
||||
cp.performAddGroup('G2');
|
||||
cp.performAdd('P1');
|
||||
cp.renderPorts(true);
|
||||
|
||||
expect(cp.performDeleteGroup(cp.findGroupWithName('G2')).success).toBe(true);
|
||||
expect(c.findPortWithName('P1').group).toBe(undefined);
|
||||
});
|
||||
});
|
||||
536
packages/noodl-editor/tests/components/componentspanel.js
Normal file
@@ -0,0 +1,536 @@
|
||||
const { ComponentsPanelView } = require('@noodl-views/panels/componentspanel/ComponentsPanel');
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const { UndoQueue } = require('@noodl-models/undo-queue-model');
|
||||
const NodeGraphEditor = require('@noodl-views/nodegrapheditor').NodeGraphEditor;
|
||||
const ViewerConnection = require('../../src/editor/src/ViewerConnection');
|
||||
|
||||
describe('Components panel unit tests', function () {
|
||||
var cp;
|
||||
var p1;
|
||||
|
||||
var project = {
|
||||
components: [
|
||||
{
|
||||
name: 'Root',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/test/f1/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/test/f2/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/b',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/test/ff/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/q',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/dup/f1/a',
|
||||
graph: {}
|
||||
},
|
||||
// Undo tests
|
||||
{
|
||||
name: '/delete_folder/delete_comp',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/rename_folder/rename_comp',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/drop/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/drop2/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/dropundo',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/nested-target/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/nested-dropme/test/b',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/delete-me/with-content/a',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/delete-me/b',
|
||||
graph: {}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
// Mock node graph editor
|
||||
NodeGraphEditor.instance = {
|
||||
getActiveComponent() {
|
||||
return p1.getComponentWithName('Root');
|
||||
},
|
||||
on() {},
|
||||
off() {},
|
||||
switchToComponent() {}
|
||||
};
|
||||
|
||||
// Viewerconnection mock
|
||||
ViewerConnection.instance = {
|
||||
on() {},
|
||||
off() {}
|
||||
};
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
NodeGraphEditor.instance = undefined;
|
||||
ViewerConnection.instance = undefined;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
p1 = ProjectModel.instance = ProjectModel.fromJSON(project);
|
||||
cp = new ComponentsPanelView({});
|
||||
cp.setNodeGraphEditor(NodeGraphEditor.instance);
|
||||
cp.render();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cp.dispose();
|
||||
ProjectModel.instance = undefined;
|
||||
});
|
||||
|
||||
it('can setup view', function () {
|
||||
expect(cp).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can add new folders', function () {
|
||||
// Existing folder
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'folder',
|
||||
name: 'test'
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Empty name
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'folder',
|
||||
name: ''
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Add
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'folder',
|
||||
name: 'f3'
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(cp.getFolderWithPath('/f3/')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can add components', function () {
|
||||
// Existing name
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'component',
|
||||
name: 'b',
|
||||
parentPath: '/'
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Empty name
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'component',
|
||||
name: ''
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Add
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'component',
|
||||
name: 'c',
|
||||
parentPath: '/'
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/c')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/').hasComponentWithName('c')).toBe(true);
|
||||
|
||||
// Add to sub directory
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'component',
|
||||
name: 'subsub',
|
||||
parentPath: '/test/ff/'
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/test/ff/subsub')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/test/ff/').hasComponentWithName('subsub')).toBe(true);
|
||||
});
|
||||
|
||||
it('can rename folders', function () {
|
||||
// Existing name
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'folder',
|
||||
name: 'f2',
|
||||
folder: cp.getFolderWithPath('/test/ff/')
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Empty name
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'folder',
|
||||
name: '',
|
||||
folder: cp.getFolderWithPath('/test/ff/')
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Empty name
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'folder',
|
||||
name: 'f4',
|
||||
folder: cp.getFolderWithPath('/test/ff/')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/test/ff/a')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/test/f4/a')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/test/ff/')).toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/test/f4/')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can rename components', function () {
|
||||
// Existing name
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'component',
|
||||
name: 'b',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/q')
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Empty name
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'component',
|
||||
name: '',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/q')
|
||||
}).success
|
||||
).toBe(false);
|
||||
|
||||
// Empty name
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'component',
|
||||
name: 'q2',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/q')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/q')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/q2')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can detect duplicates', function () {
|
||||
// Cannot move to folder containing a comp with same name
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'component',
|
||||
component: p1.getComponentWithName('/a'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f1/')
|
||||
})
|
||||
).toBe(false);
|
||||
|
||||
// Cannot move folder to folder containing a folder with same name
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/dup/f1/'),
|
||||
targetFolder: cp.getFolderWithPath('/test/')
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('can make correct drops of folders', function () {
|
||||
// Can move a folder into a folder
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/test/f1/'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f2/')
|
||||
})
|
||||
).toBe('folder');
|
||||
|
||||
// Make the move
|
||||
cp.dropOn({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/test/f1/'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f2/')
|
||||
});
|
||||
|
||||
expect(p1.getComponentWithName('/test/f2/f1/a')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/test/f2/f1/').name).toBe('f1');
|
||||
// expect(cp.getFolderWithPath('/test/f1/')).toBe(undefined);
|
||||
|
||||
// Moving to an ancestor or same folder should not be acceptable
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/test/f2/'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f2/f1/')
|
||||
})
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/test/f2/'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f2/')
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('can make correct drops of components', function () {
|
||||
// Can move into a new folder
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'component',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/b'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f2/')
|
||||
})
|
||||
).toBe('component');
|
||||
|
||||
// Cannot drop to same folder
|
||||
expect(
|
||||
cp.getAcceptableDropType({
|
||||
type: 'component',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/b'),
|
||||
targetFolder: cp.getFolderWithPath('/')
|
||||
})
|
||||
).toBe(false);
|
||||
|
||||
// Make the drop
|
||||
cp.dropOn({
|
||||
type: 'component',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/b'),
|
||||
targetFolder: cp.getFolderWithPath('/test/f2/')
|
||||
});
|
||||
|
||||
expect(p1.getComponentWithName('/test/f2/b')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/').hasComponentWithName('b')).toBe(false);
|
||||
expect(cp.getFolderWithPath('/test/f2/').hasComponentWithName('b')).toBe(true);
|
||||
expect(p1.getComponentWithName('/b')).toBe(undefined);
|
||||
});
|
||||
|
||||
//TODO: empty folders are removed when moved, but the undo function does not restore them. This is a bug.
|
||||
xit('can drop empty folders', function () {
|
||||
cp.performAdd({
|
||||
type: 'folder',
|
||||
name: 'empty_folder',
|
||||
parentFolder: cp.getFolderWithPath('/')
|
||||
});
|
||||
|
||||
expect(cp.getFolderWithPath('/empty_folder/')).not.toBe(undefined);
|
||||
|
||||
// Drop empty folder
|
||||
cp.dropOn({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/empty_folder/'),
|
||||
targetFolder: cp.getFolderWithPath('/test/')
|
||||
});
|
||||
|
||||
expect(cp.getFolderWithPath('/empty_folder/')).toBe(undefined);
|
||||
//empty folders are removed when moved
|
||||
expect(cp.getFolderWithPath('/test/empty_folder/')).toBe(undefined);
|
||||
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(cp.getFolderWithPath('/empty_folder/')).not.toBe(undefined);
|
||||
// expect(cp.getFolderWithPath('/test/empty_folder/')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('can undo add/delete/rename component and folder', function () {
|
||||
// Add component
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'component',
|
||||
name: 'undome',
|
||||
parentPath: '/'
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/undome')).not.toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('add component');
|
||||
expect(p1.getComponentWithName('/undome')).toBe(undefined);
|
||||
|
||||
// Add folder
|
||||
expect(
|
||||
cp.performAdd({
|
||||
type: 'folder',
|
||||
name: 'undome',
|
||||
parentPath: '/'
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(cp.getFolderWithPath('/undome/')).not.toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('add folder');
|
||||
expect(cp.getFolderWithPath('/undome/')).toBe(undefined);
|
||||
|
||||
// Delete component
|
||||
expect(
|
||||
cp.performDelete({
|
||||
type: 'component',
|
||||
folder: cp.getFolderWithPath('/delete_folder/'),
|
||||
component: p1.getComponentWithName('/delete_folder/delete_comp')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/delete_folder/delete_comp')).toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('delete component');
|
||||
expect(p1.getComponentWithName('/delete_folder/delete_comp')).not.toBe(undefined);
|
||||
expect(UndoQueue.instance.redo().label).toBe('delete component'); // Folder must be empty for next test to run
|
||||
|
||||
// Delete folder
|
||||
expect(
|
||||
cp.performDelete({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/delete_folder/')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(cp.getFolderWithPath('/delete_folder/')).toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('delete folder');
|
||||
expect(cp.getFolderWithPath('/delete_folder/')).not.toBe(undefined);
|
||||
|
||||
// Rename component
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'component',
|
||||
name: 'newname',
|
||||
folder: cp.getFolderWithPath('/rename_folder/'),
|
||||
component: p1.getComponentWithName('/rename_folder/rename_comp')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/rename_folder/newname')).not.toBe(undefined);
|
||||
expect(p1.getComponentWithName('/rename_folder/rename_comp')).toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('rename component');
|
||||
expect(p1.getComponentWithName('/rename_folder/newname')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/rename_folder/rename_comp')).not.toBe(undefined);
|
||||
|
||||
// Rename folder
|
||||
expect(
|
||||
cp.performRename({
|
||||
type: 'folder',
|
||||
name: 'newname',
|
||||
folder: cp.getFolderWithPath('/rename_folder/')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(p1.getComponentWithName('/newname/rename_comp')).not.toBe(undefined);
|
||||
expect(p1.getComponentWithName('/rename_folder/rename_comp')).toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/rename_folder/')).toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/newname/')).not.toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('rename folder');
|
||||
expect(p1.getComponentWithName('/newname/rename_comp')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/rename_folder/rename_comp')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/rename_folder/')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/newname/')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('can undo drop on folder', function () {
|
||||
// Component on folder
|
||||
cp.dropOn({
|
||||
type: 'component',
|
||||
folder: cp.getFolderWithPath('/'),
|
||||
component: p1.getComponentWithName('/dropundo'),
|
||||
targetFolder: cp.getFolderWithPath('/drop/')
|
||||
});
|
||||
|
||||
expect(p1.getComponentWithName('/drop/dropundo')).not.toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('move component to folder');
|
||||
// expect(p1.getComponentWithName('/drop/dropundo')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/dropundo')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/drop/').hasComponentWithName('dropundo')).toBe(false);
|
||||
|
||||
// Folder on folder
|
||||
cp.dropOn({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/drop/'),
|
||||
targetFolder: cp.getFolderWithPath('/drop2/')
|
||||
});
|
||||
expect(cp.getFolderWithPath('/drop2/drop/')).not.toBe(undefined);
|
||||
expect(UndoQueue.instance.undo().label).toBe('move folder to folder');
|
||||
// expect(cp.getFolderWithPath('/drop2/drop/')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('can make correct drops of nested folders and undo', function () {
|
||||
cp.dropOn({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/nested-dropme/'),
|
||||
targetFolder: cp.getFolderWithPath('/nested-target/')
|
||||
});
|
||||
expect(cp.getFolderWithPath('/nested-target/nested-dropme/')).not.toBe(undefined);
|
||||
expect(p1.getComponentWithName('/nested-target/nested-dropme/test/b')).not.toBe(undefined);
|
||||
expect(p1.getComponentWithName('/nested-dropme/test/b')).toBe(undefined);
|
||||
// expect(cp.getFolderWithPath('/nested-dropme/')).toBe(undefined);
|
||||
UndoQueue.instance.undo();
|
||||
// expect(cp.getFolderWithPath('/nested-target/nested-dropme/')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/nested-target/nested-dropme/test/b')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/nested-dropme/test/b')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/nested-dropme/')).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can delete folder with content', function () {
|
||||
// Delete folder
|
||||
expect(
|
||||
cp.performDelete({
|
||||
type: 'folder',
|
||||
folder: cp.getFolderWithPath('/delete-me/')
|
||||
}).success
|
||||
).toBe(true);
|
||||
|
||||
expect(cp.getFolderWithPath('/delete-me/')).toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/delete-me/with-content/')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/delete-me/with-content/a')).toBe(undefined);
|
||||
expect(p1.getComponentWithName('/delete-me/b')).toBe(undefined);
|
||||
UndoQueue.instance.undo();
|
||||
expect(cp.getFolderWithPath('/delete-me/')).not.toBe(undefined);
|
||||
expect(cp.getFolderWithPath('/delete-me/with-content/')).not.toBe(undefined);
|
||||
expect(p1.getComponentWithName('/delete-me/with-content/a')).not.toBe(undefined);
|
||||
expect(p1.getComponentWithName('/delete-me/b')).not.toBe(undefined);
|
||||
});
|
||||
});
|
||||
48
packages/noodl-editor/tests/components/conditionalports.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('Conditional ports tests', function () {
|
||||
beforeEach(() => {
|
||||
ProjectModel.instance = ProjectModel.fromJSON({
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'Anim',
|
||||
id: 'A-1',
|
||||
parameters: {
|
||||
type: 'typeA'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
xit('can get correct ports after load', function () {
|
||||
var ports = ProjectModel.instance.findNodeWithId('A-1').getPorts();
|
||||
expect(ports.length).toBe(2);
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'from',
|
||||
plug: 'input',
|
||||
type: 'number',
|
||||
index: 1
|
||||
});
|
||||
});
|
||||
|
||||
xit('can react to param changes', function () {
|
||||
ProjectModel.instance.findNodeWithId('A-1').setParameter('type', 'typeB');
|
||||
|
||||
var ports = ProjectModel.instance.findNodeWithId('A-1').getPorts();
|
||||
expect(ports.length).toBe(2);
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'to',
|
||||
plug: 'input',
|
||||
type: 'number',
|
||||
index: 1
|
||||
});
|
||||
});
|
||||
});
|
||||
89
packages/noodl-editor/tests/components/dynamicports.js
Normal file
@@ -0,0 +1,89 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('Dynamic ports from viewer tests', function () {
|
||||
// Setup
|
||||
var projectJSON = {
|
||||
components: [
|
||||
{
|
||||
name: 'Root',
|
||||
graph: {
|
||||
connections: [
|
||||
{
|
||||
fromId: 'A',
|
||||
fromProperty: 'dynaA',
|
||||
toId: 'B',
|
||||
toProperty: 'x'
|
||||
},
|
||||
{
|
||||
fromId: 'B',
|
||||
fromProperty: 'y',
|
||||
toId: 'A',
|
||||
toProperty: 'dynaB'
|
||||
}
|
||||
],
|
||||
roots: [
|
||||
{
|
||||
type: 'rectangle',
|
||||
id: 'A',
|
||||
parameters: {
|
||||
dynaA: 10,
|
||||
dynaB: 'hej'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'rectangle',
|
||||
id: 'B'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var project = ProjectModel.fromJSON(projectJSON);
|
||||
|
||||
it('can rename inputs', function () {
|
||||
var n = project.findNodeWithId('A');
|
||||
|
||||
n.setDynamicPorts([
|
||||
{
|
||||
name: 'dynaA',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'dynaB',
|
||||
type: 'string'
|
||||
}
|
||||
]);
|
||||
|
||||
// Now renamed
|
||||
n.setDynamicPorts(
|
||||
[
|
||||
{
|
||||
name: 'bosseA',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'bosseB',
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
{
|
||||
renamed: {
|
||||
plug: 'input',
|
||||
patterns: ['{{*}}A', '{{*}}B'],
|
||||
before: 'dyna',
|
||||
after: 'bosse'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
expect(n.parameters['bosseA']).toBe(10);
|
||||
expect(n.parameters['bosseB']).toBe('hej');
|
||||
expect(n.parameters['dynaA']).toBe(undefined);
|
||||
expect(n.parameters['dynaB']).toBe(undefined);
|
||||
|
||||
expect(project.getComponentWithName('Root').graph.connections[0].fromProperty).toBe('bosseA');
|
||||
expect(project.getComponentWithName('Root').graph.connections[1].toProperty).toBe('bosseB');
|
||||
});
|
||||
});
|
||||
82
packages/noodl-editor/tests/components/expandedports.js
Normal file
@@ -0,0 +1,82 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('Expanded ports tests', function () {
|
||||
beforeEach(() => {
|
||||
ProjectModel.instance = ProjectModel.fromJSON(getProject());
|
||||
});
|
||||
|
||||
xit('can get correct ports after load', function () {
|
||||
var ports = ProjectModel.instance.findNodeWithId('EP-1').getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'Affe.A',
|
||||
index: 101,
|
||||
plug: 'input',
|
||||
type: 'number'
|
||||
});
|
||||
expect(ports[2]).toEqual({
|
||||
name: 'Affe.B',
|
||||
index: 102,
|
||||
plug: 'input',
|
||||
type: 'number'
|
||||
});
|
||||
});
|
||||
|
||||
xit('can react to param changes', function () {
|
||||
ProjectModel.instance.findNodeWithId('EP-1').setParameter('Affe.A', 'something');
|
||||
|
||||
var ports = ProjectModel.instance.findNodeWithId('EP-1').getPorts();
|
||||
expect(ports.length).toBe(2);
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'Affe.A',
|
||||
index: 101,
|
||||
plug: 'input',
|
||||
type: 'number'
|
||||
});
|
||||
});
|
||||
|
||||
xit('can rename ports and parameters are copied', function () {
|
||||
ProjectModel.instance.findNodeWithId('EP-2').setParameter('Bosse.A', 'grr');
|
||||
|
||||
ProjectModel.instance.findNodeWithId('EP-2').renamePortWithName('Bosse', 'Oscar');
|
||||
|
||||
expect(ProjectModel.instance.findNodeWithId('EP-2').parameters['Oscar.A']).toBe('grr');
|
||||
expect(ProjectModel.instance.findNodeWithId('EP-2').parameters['Bosse.A']).toBe(undefined);
|
||||
});
|
||||
|
||||
function getProject() {
|
||||
return {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'ExpandPorts',
|
||||
id: 'EP-1',
|
||||
ports: [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'Affe',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'ExpandPorts',
|
||||
id: 'EP-2',
|
||||
ports: [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'Bosse',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
9
packages/noodl-editor/tests/components/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export * from './componentconnections';
|
||||
export * from './componentinstances';
|
||||
export * from './componentports';
|
||||
export * from './componentspanel';
|
||||
export * from './conditionalports';
|
||||
export * from './dynamicports';
|
||||
export * from './expandedports';
|
||||
export * from './numberedports';
|
||||
export * from './portchannels';
|
||||
100
packages/noodl-editor/tests/components/numberedports.js
Normal file
@@ -0,0 +1,100 @@
|
||||
const NodeGraphModel = require('@noodl-models/nodegraphmodel').NodeGraphModel;
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
|
||||
describe('Numbered ports tests', function () {
|
||||
var g1, e1, e2, e3;
|
||||
|
||||
beforeEach(() => {
|
||||
g1 = new NodeGraphModel();
|
||||
e1 = NodeGraphNode.fromJSON({
|
||||
id: 'A',
|
||||
type: 'nodeWithNumberedPorts'
|
||||
});
|
||||
|
||||
g1.addRoot(e1);
|
||||
});
|
||||
|
||||
xit('can add new ports dynamically', function () {
|
||||
var ports = e1.getPorts();
|
||||
expect(ports.length).toBe(1);
|
||||
expect(ports[0].name).toBe('my number 0');
|
||||
expect(ports[0].displayName).toBe('My number 0');
|
||||
expect(ports[0].type).toBe('number');
|
||||
expect(ports[0].group).toBe('My group');
|
||||
|
||||
e1.setParameter('my number 0', 10);
|
||||
var ports = e1.getPorts();
|
||||
expect(ports.length).toBe(2);
|
||||
expect(ports[1].name).toBe('my number 1');
|
||||
expect(ports[1].displayName).toBe('My number 1');
|
||||
});
|
||||
|
||||
xit('can find highest parameter', function () {
|
||||
// The number of parameters should be defined by the highest parameter that is
|
||||
// not undefined
|
||||
e1.setParameter('my number 1', 20);
|
||||
var ports = e1.getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
|
||||
// Setting to undefined should still be there because 'my number 1' is 20
|
||||
e1.setParameter('my number 0', undefined);
|
||||
var ports = e1.getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
});
|
||||
|
||||
xit('can detect connections', function () {
|
||||
e2 = NodeGraphNode.fromJSON({
|
||||
id: 'B',
|
||||
type: 'nodeWithNumberedPorts'
|
||||
});
|
||||
g1.addRoot(e2);
|
||||
|
||||
g1.addConnection({
|
||||
fromId: 'A',
|
||||
fromProperty: 'my number 2',
|
||||
toId: 'B',
|
||||
toProperty: 'my number 1'
|
||||
});
|
||||
|
||||
// A should now have 4 ports (connected to my number 2)
|
||||
var ports = e1.getPorts();
|
||||
expect(ports.length).toBe(4);
|
||||
|
||||
// B should have 3 ports (connected to my number 1)
|
||||
var ports = e2.getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
});
|
||||
|
||||
xit('can generate selectors', function () {
|
||||
e3 = NodeGraphNode.fromJSON({
|
||||
id: 'C',
|
||||
type: 'nodeWithNumberedPortsAndSelectors'
|
||||
});
|
||||
g1.addRoot(e3);
|
||||
|
||||
var ports = e3.getPorts();
|
||||
expect(ports.length).toBe(2);
|
||||
expect(ports[1].name).toBe('startAt');
|
||||
expect(ports[1].group).toBe('My selectors');
|
||||
expect(ports[1].type.enums.length).toBe(0);
|
||||
expect(ports[1].type.name).toBe('enum');
|
||||
|
||||
// Add a dynamic port, should be listed in the selector
|
||||
e3.setParameter('my number 0', 10);
|
||||
var ports = e3.getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
expect(ports[2].type.enums.length).toBe(1);
|
||||
expect(ports[2].type.enums[0].value).toBe('my number 0');
|
||||
expect(ports[2].type.enums[0].label).toBe('My number 0');
|
||||
|
||||
// More
|
||||
e3.setParameter('my number 1', 20);
|
||||
var ports = e3.getPorts();
|
||||
expect(ports.length).toBe(4);
|
||||
expect(ports[3].type.enums.length).toBe(2);
|
||||
expect(ports[3].type.enums[0].value).toBe('my number 0');
|
||||
expect(ports[3].type.enums[0].label).toBe('My number 0');
|
||||
expect(ports[3].type.enums[1].value).toBe('my number 1');
|
||||
expect(ports[3].type.enums[1].label).toBe('My number 1');
|
||||
});
|
||||
});
|
||||
191
packages/noodl-editor/tests/components/portchannels.js
Normal file
@@ -0,0 +1,191 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('Port channels tests', function () {
|
||||
beforeEach(() => {
|
||||
ProjectModel.instance = ProjectModel.fromJSON(getProject());
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
//unregister the project model so subsequent tests arent affected
|
||||
//(the channels can affect other tests)
|
||||
ProjectModel.instance = undefined;
|
||||
});
|
||||
|
||||
xit('can collect channel names', function () {
|
||||
var ports = ProjectModel.instance.findNodeWithId('ER-1').getPorts();
|
||||
expect(ports.length).toBe(1);
|
||||
expect(ports[0].name).toBe('channel');
|
||||
expect(ports[0].type).toEqual({
|
||||
name: 'enum',
|
||||
enums: ['channelA', 'channelB'],
|
||||
allowEditOnly: true
|
||||
});
|
||||
});
|
||||
|
||||
xit('can collect ports when channel name is set', function () {
|
||||
ProjectModel.instance.findNodeWithId('ER-1').setParameter('channel', 'channelA');
|
||||
|
||||
var ports = ProjectModel.instance.findNodeWithId('ER-1').getPorts();
|
||||
expect(ports.length).toBe(4);
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'p1',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 1
|
||||
});
|
||||
expect(ports[2]).toEqual({
|
||||
name: 'p2',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 2
|
||||
});
|
||||
expect(ports[3]).toEqual({
|
||||
name: 'p3',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 3
|
||||
});
|
||||
});
|
||||
|
||||
xit('can react to port name change', function () {
|
||||
ProjectModel.instance.findNodeWithId('ER-1').setParameter('channel', 'channelA');
|
||||
ProjectModel.instance.findNodeWithId('ES-1').renamePortWithName('p2', 'p2b');
|
||||
|
||||
var ports = ProjectModel.instance.findNodeWithId('ER-1').getPorts();
|
||||
expect(ports.length).toBe(5);
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'p1',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 1
|
||||
});
|
||||
expect(ports[2]).toEqual({
|
||||
name: 'p2',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 2
|
||||
});
|
||||
expect(ports[3]).toEqual({
|
||||
name: 'p2b',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 3
|
||||
});
|
||||
expect(ports[4]).toEqual({
|
||||
name: 'p3',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 4
|
||||
});
|
||||
});
|
||||
|
||||
xit('can react to channel changes', function () {
|
||||
ProjectModel.instance.findNodeWithId('ER-1').setParameter('channel', 'channelA');
|
||||
ProjectModel.instance.findNodeWithId('ES-1').setParameter('channel', 'channelC');
|
||||
|
||||
var ports = ProjectModel.instance.findNodeWithId('ER-1').getPorts();
|
||||
expect(ports.length).toBe(3);
|
||||
expect(ports[0].name).toBe('channel');
|
||||
expect(ports[0].type).toEqual({
|
||||
name: 'enum',
|
||||
enums: ['channelA', 'channelB', 'channelC'],
|
||||
allowEditOnly: true
|
||||
});
|
||||
expect(ports[1]).toEqual({
|
||||
name: 'p2',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 1
|
||||
});
|
||||
expect(ports[2]).toEqual({
|
||||
name: 'p3',
|
||||
type: '*',
|
||||
plug: 'output',
|
||||
index: 2
|
||||
});
|
||||
});
|
||||
|
||||
function getProject() {
|
||||
return {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'Event Sender',
|
||||
id: 'ES-1',
|
||||
parameters: {
|
||||
channel: 'channelA'
|
||||
},
|
||||
ports: [
|
||||
{
|
||||
name: 'p1',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'p2',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'Event Receiver',
|
||||
id: 'ER-1'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'Event Sender',
|
||||
id: 'ES-2',
|
||||
parameters: {
|
||||
channel: 'channelA'
|
||||
},
|
||||
ports: [
|
||||
{
|
||||
name: 'p2',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'p3',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'Event Sender',
|
||||
id: 'ES-3',
|
||||
parameters: {
|
||||
channel: 'channelB'
|
||||
},
|
||||
ports: [
|
||||
{
|
||||
name: 'p3',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'p4',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
// https://codehandbook.org/check-if-an-array-sorted-javascript/
|
||||
// Check if an array is sorted in order.
|
||||
function sorted(arr: number[]) {
|
||||
let second_index: number;
|
||||
for (let first_index = 0; first_index < arr.length; first_index++) {
|
||||
second_index = first_index + 1;
|
||||
if (arr[second_index] - arr[first_index] < 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
describe('Git clone progress tests', function () {
|
||||
let tempDir: string | undefined;
|
||||
|
||||
beforeEach(async function () {
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('clone from "master" with progress', async function () {
|
||||
const result = [];
|
||||
|
||||
// Clone the project
|
||||
const git = new Git(mergeProject);
|
||||
await git.clone({
|
||||
url: 'https://github.com/github/testrepo.git',
|
||||
directory: tempDir,
|
||||
onProgress: (progress) => {
|
||||
result.push(progress);
|
||||
}
|
||||
});
|
||||
|
||||
const values = result.map((x) => x.value);
|
||||
const isValuesSorted = sorted(values);
|
||||
|
||||
expect(result.length).toBeGreaterThan(10);
|
||||
expect(isValuesSorted).toBeTrue();
|
||||
});
|
||||
|
||||
it('clone and fetch with progress', async function () {
|
||||
const result = [];
|
||||
|
||||
// Create empty repo
|
||||
const git = new Git(mergeProject);
|
||||
await git.clone({
|
||||
url: 'https://github.com/github/testrepo.git',
|
||||
directory: tempDir,
|
||||
onProgress: (progress) => {
|
||||
result.push(progress);
|
||||
}
|
||||
});
|
||||
|
||||
await git.checkoutBranch('master', '6ff1be9c3819c93a2f41e0ddc09f252fcf154f34');
|
||||
|
||||
// Fetch from remote
|
||||
await git.fetch({
|
||||
onProgress: (progress) => {
|
||||
result.push(progress);
|
||||
}
|
||||
});
|
||||
|
||||
const values = result.map((x) => x.value);
|
||||
const isValuesSorted = sorted(values);
|
||||
|
||||
expect(result.length).toBeGreaterThan(10);
|
||||
expect(isValuesSorted).toBeTrue();
|
||||
});
|
||||
});
|
||||
59
packages/noodl-editor/tests/git/git-diff.spec.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
describe('Git diff tests', function () {
|
||||
let git: Git;
|
||||
let tempDir: string;
|
||||
|
||||
beforeEach(async function () {
|
||||
// Logger.log(`[jest-before]: ${expect.getState().currentTestName}`)
|
||||
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
// await git.commit("initial commit"); //commit .gitattributes so we have a clean repo
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`)
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('can diff files between commits', async function () {
|
||||
FileSystem.instance.writeFileSync(tempDir + 'initial.txt', 'hello world');
|
||||
await git.commit('initial commit');
|
||||
|
||||
const commit0 = await git.getHeadCommitId();
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file.txt', 'text');
|
||||
await git.commit('added file');
|
||||
|
||||
const commit1 = await git.getHeadCommitId();
|
||||
let diff = await git.getFileDiff(commit0, commit1);
|
||||
expect(diff).toEqual([
|
||||
{
|
||||
status: 'new',
|
||||
path: 'file.txt'
|
||||
}
|
||||
]);
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file.txt', 'text2');
|
||||
await git.commit('modified file');
|
||||
|
||||
const commit2 = await git.getHeadCommitId();
|
||||
diff = await git.getFileDiff(commit1, commit2);
|
||||
expect(diff).toEqual([
|
||||
{
|
||||
status: 'modified',
|
||||
path: 'file.txt'
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
160
packages/noodl-editor/tests/git/git-local-merge.spec.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
// TODO: Stash untracked files ?
|
||||
|
||||
async function readTextFile(path) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
FileSystem.instance.readTextFile(path, (text) => {
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Git local tests', function () {
|
||||
let git: Git;
|
||||
let tempDir: string | undefined;
|
||||
|
||||
beforeEach(async function () {
|
||||
// Logger.log(`[jest-before]: ${expect.getState().currentTestName}`);
|
||||
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
|
||||
// The new version doesnt make a first commit
|
||||
FileSystem.instance.writeFileSync(tempDir + 'initial.txt', 'Hello World');
|
||||
await git.commit('initial commit');
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('can handle merge conflicts in files', async function () {
|
||||
//commit new file on main
|
||||
const path = tempDir + 'test.txt';
|
||||
|
||||
FileSystem.instance.writeFileSync(path, 'original');
|
||||
await git.commit('added new file');
|
||||
|
||||
//create new brach, change the file, and commit it
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
FileSystem.instance.writeFileSync(path, 'test-branch');
|
||||
await git.commit('modified file');
|
||||
|
||||
//move back to main, and change the file
|
||||
await git.checkoutBranch('main');
|
||||
FileSystem.instance.writeFileSync(path, 'main');
|
||||
|
||||
//and now merge in the test brach. Should automatically resolve the conflict to "ours"
|
||||
await git.mergeToCurrentBranch('test-branch');
|
||||
const file = await readTextFile(path);
|
||||
expect(file).toBe('main');
|
||||
|
||||
// Status should show test.txt as modified
|
||||
const status = await git.status();
|
||||
expect(status).toEqual([{ status: 'modified', path: 'test.txt' }]);
|
||||
});
|
||||
|
||||
it('can handle merge without conflicts in project.json', async function () {
|
||||
//commit project on main
|
||||
const path = tempDir + 'project.json';
|
||||
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(simpleProject()));
|
||||
await git.commit('added original project');
|
||||
|
||||
//create new brach, change the project, and commit it
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
await git.checkoutBranch('test-branch');
|
||||
|
||||
const modifiedProjectTestBranch = simpleProject();
|
||||
modifiedProjectTestBranch.components[0].graph.roots[0].parameters.text = 'test-branch';
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(modifiedProjectTestBranch));
|
||||
await git.commit('modified project');
|
||||
|
||||
//move back to main, and merge in the test branch
|
||||
await git.checkoutBranch('main');
|
||||
await git.mergeToCurrentBranch('test-branch');
|
||||
const proj = JSON.parse(await readTextFile(path));
|
||||
|
||||
const conflicts = proj.components[0].graph.roots[0].conflicts;
|
||||
expect(conflicts).toBe(undefined);
|
||||
expect(proj.components[0].graph.roots[0].parameters.text).toBe('test-branch');
|
||||
|
||||
//status should be empty
|
||||
expect(await git.status()).toEqual([]);
|
||||
});
|
||||
|
||||
it('can handle merge with conflicts in project.json', async function () {
|
||||
//commit project on main
|
||||
const path = tempDir + 'project.json';
|
||||
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(simpleProject()));
|
||||
await git.commit('added original project');
|
||||
|
||||
//create new brach, change the project, and commit it
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
await git.checkoutBranch('test-branch');
|
||||
|
||||
const modifiedProjectTestBranch = simpleProject();
|
||||
modifiedProjectTestBranch.components[0].graph.roots[0].parameters.text = 'test-branch';
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(modifiedProjectTestBranch));
|
||||
await git.commit('modified project');
|
||||
|
||||
//move back to main, and change the project again
|
||||
await git.checkoutBranch('main');
|
||||
const modifiedProjectMaster = simpleProject();
|
||||
modifiedProjectMaster.components[0].graph.roots[0].parameters.text = 'main';
|
||||
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(modifiedProjectMaster));
|
||||
|
||||
//and now merge in the test brach. Should automatically result in conflicts in project
|
||||
await git.mergeToCurrentBranch('test-branch');
|
||||
const proj = JSON.parse(await readTextFile(path));
|
||||
|
||||
const conflicts = proj.components[0].graph.roots[0].conflicts;
|
||||
expect(conflicts.length).toBe(1);
|
||||
expect(conflicts[0].name).toBe('text');
|
||||
expect(conflicts[0].ours).toBe('main');
|
||||
expect(conflicts[0].theirs).toBe('test-branch');
|
||||
|
||||
//check that status is contains a modified project.json
|
||||
expect(await git.status()).toEqual([{ status: 'modified', path: 'project.json' }]);
|
||||
});
|
||||
|
||||
function simpleProject() {
|
||||
return {
|
||||
name: 'proj',
|
||||
components: [
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'c8451024-fe91-0cbe-b3ad-85d77dd01432',
|
||||
type: 'Text',
|
||||
x: 237,
|
||||
y: 170,
|
||||
parameters: {
|
||||
text: 'original'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
rootNodeId: 'c8451024-fe91-0cbe-b3ad-85d77dd01432',
|
||||
version: '1'
|
||||
};
|
||||
}
|
||||
});
|
||||
44
packages/noodl-editor/tests/git/git-local-misc.spec.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import Process from 'process';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
describe('git local misc', () => {
|
||||
//Read project.json from the filesystem using using node, and then read the same file from the HEAD commit using git. They should be equal.
|
||||
//This will test the character encoding, and the test project contains a few special characters
|
||||
it('reads files with the correct encoding', async () => {
|
||||
const testFilePath = Process.cwd() + '/tests/testfs/git-repo-utf8/';
|
||||
|
||||
//create a temp folder with the test project.json file
|
||||
const tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
FileSystem.instance.copyRecursiveSync(testFilePath, tempDir);
|
||||
|
||||
//create a new git repo and commit the file
|
||||
const git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
await git.commit('test');
|
||||
|
||||
//read project.json from the filesystem
|
||||
const projectFromFS = JSON.parse(FileSystem.instance.readFileSync(tempDir + 'project.json'));
|
||||
|
||||
//and read the same file from the HEAD commit
|
||||
const headCommitId = await git.getHeadCommitId();
|
||||
const headCommit = await git.getCommitFromId(headCommitId);
|
||||
expect(headCommit).toBeTruthy();
|
||||
const projectJson = await headCommit.getFileAsString('project.json');
|
||||
const project = JSON.parse(projectJson);
|
||||
expect(project).toBeTruthy();
|
||||
|
||||
//and compare
|
||||
expect(projectFromFS).toEqual(project);
|
||||
|
||||
//clean up
|
||||
await new Promise((resolve) => {
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
403
packages/noodl-editor/tests/git/git-local.spec.ts
Normal file
@@ -0,0 +1,403 @@
|
||||
import path from 'path';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
// TODO: Stash untracked files ?
|
||||
|
||||
async function readTextFile(path) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
FileSystem.instance.readTextFile(path, (text) => {
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Git local tests', function () {
|
||||
let git: Git;
|
||||
let tempDir: string | undefined;
|
||||
|
||||
beforeEach(async function () {
|
||||
// Logger.log(`[jest-before]: ${expect.getState().currentTestName}`);
|
||||
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
|
||||
// The new version doesnt make a first commit
|
||||
FileSystem.instance.writeFileSync(tempDir + 'initial.txt', 'Hello World');
|
||||
await git.commit('initial commit');
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('new repo has correct config and no changes', async function () {
|
||||
const text = await readTextFile(tempDir + '.git/config');
|
||||
|
||||
expect(text.includes('precomposeUnicode = true')).toBe(true);
|
||||
|
||||
expect(text.includes('[merge "noodl"]')).toBe(true);
|
||||
|
||||
expect(await git.status()).toEqual([]);
|
||||
});
|
||||
|
||||
it('can get head commit', async function () {
|
||||
const head = await git.getHeadCommitId();
|
||||
expect(head).toHaveSize(40); // git commit hash length
|
||||
});
|
||||
|
||||
it('can get remote commit', async function () {
|
||||
//we have no remote, so it should be null
|
||||
const head = await git.getRemoteHeadCommitId();
|
||||
expect(head).toBe(null);
|
||||
});
|
||||
|
||||
it('can commit a new file', async function () {
|
||||
//add a new file
|
||||
FileSystem.instance.writeFileSync(tempDir + 'test.txt', 'hej');
|
||||
|
||||
//status should reflect the new file
|
||||
let status = await git.status();
|
||||
expect(status.length).toBe(1);
|
||||
expect(status[0].path).toBe('test.txt');
|
||||
expect(status[0].status).toBe('new');
|
||||
|
||||
//commit the file
|
||||
await git.commit('added new file');
|
||||
|
||||
//now git status should be empty
|
||||
status = await git.status();
|
||||
expect(status.length).toBe(0);
|
||||
|
||||
//and read it's content to make sure it wasn't modified
|
||||
const text = await readTextFile(tempDir + 'test.txt');
|
||||
expect(text).toBe('hej');
|
||||
});
|
||||
|
||||
it('can reset untracked files', async function () {
|
||||
//add a new file
|
||||
const path = tempDir + 'test.txt';
|
||||
|
||||
FileSystem.instance.writeFileSync(path, 'hej');
|
||||
expect(FileSystem.instance.fileExistsSync(path)).toBe(true);
|
||||
|
||||
await git.resetToHead();
|
||||
|
||||
expect(FileSystem.instance.fileExistsSync(path)).toBe(false);
|
||||
const status = await git.status();
|
||||
expect(status.length).toBe(0);
|
||||
});
|
||||
|
||||
it('can reset changed files', async function () {
|
||||
//add a new file
|
||||
const path = tempDir + 'test.txt';
|
||||
|
||||
//add file and commit it
|
||||
FileSystem.instance.writeFileSync(path, 'hej');
|
||||
await git.commit('added new file');
|
||||
|
||||
//change the file content
|
||||
FileSystem.instance.writeFileSync(path, 'hej2');
|
||||
expect(await readTextFile(path)).toBe('hej2');
|
||||
|
||||
await git.resetToHead();
|
||||
|
||||
expect(await readTextFile(path)).toBe('hej');
|
||||
|
||||
//check that status is empty
|
||||
const status = await git.status();
|
||||
expect(status.length).toBe(0);
|
||||
});
|
||||
|
||||
it('can create and checkout a new branch', async function () {
|
||||
expect(await git.getCurrentBranchName()).toBe('main');
|
||||
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
await git.checkoutBranch('test-branch');
|
||||
expect(await git.getCurrentBranchName()).toBe('test-branch');
|
||||
|
||||
//check that status is empty
|
||||
const status = await git.status();
|
||||
expect(status.length).toBe(0);
|
||||
});
|
||||
|
||||
it('can list all branches', async function () {
|
||||
expect(await git.getBranches()).toEqual([{ name: 'main', local: true, remote: false }]);
|
||||
|
||||
await git.createAndCheckoutBranch('test-branch-1');
|
||||
await git.createAndCheckoutBranch('test-branch-2');
|
||||
|
||||
const branches = await git.getBranches();
|
||||
|
||||
expect(branches[0]).toEqual({ name: 'main', local: true, remote: false });
|
||||
expect(branches[1]).toEqual({
|
||||
name: 'test-branch-1',
|
||||
local: true,
|
||||
remote: false
|
||||
});
|
||||
expect(branches[2]).toEqual({
|
||||
name: 'test-branch-2',
|
||||
local: true,
|
||||
remote: false
|
||||
});
|
||||
});
|
||||
|
||||
it('can list commits from different branches', async function () {
|
||||
const path = tempDir + 'test.txt';
|
||||
|
||||
await git.createAndCheckoutBranch('test-branch-1');
|
||||
await git.checkoutBranch('test-branch-1');
|
||||
|
||||
//commit new file on test-branch
|
||||
FileSystem.instance.writeFileSync(path, 'text file');
|
||||
await git.commit('added new file');
|
||||
|
||||
await git.checkoutBranch('main');
|
||||
let commits = await git.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(1);
|
||||
expect(commits[0].message).toBe('initial commit');
|
||||
|
||||
await git.checkoutBranch('test-branch-1');
|
||||
commits = await git.getCommitsCurrentBranch();
|
||||
|
||||
//latest first
|
||||
expect(commits.length).toBe(2);
|
||||
expect(commits[0].message).toBe('added new file');
|
||||
expect(commits[1].message).toBe('initial commit');
|
||||
|
||||
//back to main, shouldn't see the commit on the other branch
|
||||
await git.checkoutBranch('main');
|
||||
commits = await git.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(1);
|
||||
expect(commits[0].message).toBe('initial commit');
|
||||
});
|
||||
|
||||
it('can list commits', async function () {
|
||||
//do a new commit
|
||||
FileSystem.instance.writeFileSync(tempDir + 'test.txt', 'text file');
|
||||
await git.commit('added new file');
|
||||
|
||||
const commits = await git.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(2);
|
||||
|
||||
//latest first
|
||||
expect(commits[0].message).toBe('added new file');
|
||||
expect(commits[0].parentCount).toBe(1);
|
||||
expect(commits[1].message).toBe('initial commit');
|
||||
expect(commits[1].parentCount).toBe(0);
|
||||
});
|
||||
|
||||
it('throws nice error message when creating invalid branches', async function () {
|
||||
await expectAsync(git.createAndCheckoutBranch('main')).toBeRejectedWithError('Branch already exists');
|
||||
await expectAsync(git.createAndCheckoutBranch(')(*&^%$')).toBeRejectedWithError(
|
||||
'Branch name contains invalid characters.'
|
||||
);
|
||||
});
|
||||
|
||||
it('can delete a local branch', async function () {
|
||||
await git.createBranchFromHead('test');
|
||||
await git.deleteBranch('test');
|
||||
|
||||
expect(await git.getBranches()).toEqual([{ name: 'main', local: true, remote: false }]);
|
||||
});
|
||||
|
||||
it('fails when deleting a non-existing branch', async function () {
|
||||
await expectAsync(git.deleteBranch('test')).toBeRejectedWithError("Branch doesn't exist");
|
||||
});
|
||||
|
||||
it('remembers local changes per branch using the stash', async function () {
|
||||
const path = tempDir + 'test.txt';
|
||||
|
||||
//commit a file
|
||||
FileSystem.instance.writeFileSync(path, 'original');
|
||||
await git.commit('added the file');
|
||||
|
||||
//make a local change
|
||||
FileSystem.instance.writeFileSync(path, 'main');
|
||||
|
||||
//create a few branches and make changes on each, without committing
|
||||
await git.createBranchFromHead('test-1');
|
||||
await git.checkoutBranch('test-1');
|
||||
FileSystem.instance.writeFileSync(path, 'test-1');
|
||||
|
||||
await git.createBranchFromHead('test-2');
|
||||
await git.checkoutBranch('test-2');
|
||||
FileSystem.instance.writeFileSync(path, 'test-2');
|
||||
|
||||
//checkout all branches and make sure the local changes are re-applied
|
||||
await git.checkoutBranch('main');
|
||||
expect(await readTextFile(path)).toBe('main');
|
||||
|
||||
await git.checkoutBranch('test-1');
|
||||
expect(await readTextFile(path)).toBe('test-1');
|
||||
|
||||
await git.checkoutBranch('test-2');
|
||||
expect(await readTextFile(path)).toBe('test-2');
|
||||
|
||||
//and back again, just to make sure :)
|
||||
await git.checkoutBranch('test-1');
|
||||
expect(await readTextFile(path)).toBe('test-1');
|
||||
|
||||
await git.checkoutBranch('main');
|
||||
expect(await readTextFile(path)).toBe('main');
|
||||
});
|
||||
|
||||
it('brings the local changes to a newly created branch', async function () {
|
||||
const path = tempDir + 'test.txt';
|
||||
|
||||
//commit a file
|
||||
FileSystem.instance.writeFileSync(path, 'original');
|
||||
await git.commit('added the file');
|
||||
|
||||
//make a local change
|
||||
FileSystem.instance.writeFileSync(path, 'change');
|
||||
|
||||
//create a new branch, it should get the changes
|
||||
await git.createAndCheckoutBranch('test-1');
|
||||
expect(await readTextFile(path)).toBe('change');
|
||||
|
||||
//and move it over to yet another new branch
|
||||
await git.createAndCheckoutBranch('test-2');
|
||||
expect(await readTextFile(path)).toBe('change');
|
||||
|
||||
//checkout all other branches and make sure they don't have any changes
|
||||
await git.checkoutBranch('main');
|
||||
FileSystem.instance.writeFileSync(path, 'original');
|
||||
|
||||
await git.checkoutBranch('test-1');
|
||||
FileSystem.instance.writeFileSync(path, 'original');
|
||||
|
||||
//and that test-2 still have them
|
||||
await git.checkoutBranch('test-2');
|
||||
expect(await readTextFile(path)).toBe('change');
|
||||
});
|
||||
|
||||
it('brings the local changes to a newly created branch - with project.json', async function () {
|
||||
//commit project on main
|
||||
const path = tempDir + 'project.json';
|
||||
const projectJson = simpleProject();
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(projectJson));
|
||||
await git.commit('added original project');
|
||||
|
||||
//modify project without committing
|
||||
projectJson.components[0].graph.roots[0].parameters.text = 'modified';
|
||||
FileSystem.instance.writeFileSync(path, JSON.stringify(projectJson));
|
||||
|
||||
//create a new brach and do a checkout
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
|
||||
//check that the previous uncommitted change is on the new branch
|
||||
expect(await git.status()).toEqual([{ status: 'modified', path: 'project.json' }]);
|
||||
const p = JSON.parse(await readTextFile(path));
|
||||
expect(p).toEqual(projectJson);
|
||||
|
||||
//move back to main, and the local changes shouldn't be here anymore
|
||||
await git.checkoutBranch('main');
|
||||
expect(await git.status()).toEqual([]);
|
||||
});
|
||||
|
||||
it('can create and checkout new branches when there are no local changes', async function () {
|
||||
//commit a file
|
||||
FileSystem.instance.writeFileSync(tempDir + 'my-file.txt', 'original');
|
||||
await git.commit('added the file');
|
||||
|
||||
//create a new brach and do a checkout
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
|
||||
expect(await git.status()).toEqual([]);
|
||||
expect(await git.getCurrentBranchName()).toEqual('test-branch');
|
||||
|
||||
const commits = await git.getCommitsCurrentBranch();
|
||||
expect(commits.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should leave local changes intact even if a checkout fails', async function () {
|
||||
const path = tempDir + 'test.txt';
|
||||
FileSystem.instance.writeFileSync(path, 'local change');
|
||||
|
||||
await expectAsync(git.checkoutBranch('non-existing-branch')).toBeRejected();
|
||||
|
||||
expect(await readTextFile(path)).toBe('local change');
|
||||
});
|
||||
|
||||
it('should leave local changes intact even if a merge fails', async function () {
|
||||
const path = tempDir + 'test.txt';
|
||||
FileSystem.instance.writeFileSync(path, 'local change');
|
||||
|
||||
await expectAsync(git.mergeToCurrentBranch('non-existing-branch')).toBeRejected();
|
||||
|
||||
expect(await readTextFile(path)).toBe('local change');
|
||||
});
|
||||
|
||||
it('should leave local changes intact even if creating a branch fails', async function () {
|
||||
const path = tempDir + 'test.txt';
|
||||
FileSystem.instance.writeFileSync(path, 'local change');
|
||||
|
||||
await expectAsync(git.createAndCheckoutBranch('invalid &*^%')).toBeRejected();
|
||||
|
||||
expect(await readTextFile(path)).toBe('local change');
|
||||
});
|
||||
|
||||
it("ignores files that shouldn't be added to the repo", async function () {
|
||||
FileSystem.instance.writeFileSync(tempDir + 'project-tmp.json', 'test');
|
||||
FileSystem.instance.writeFileSync(tempDir + '.DS_Store', 'test');
|
||||
|
||||
expect(await git.status()).toEqual([]);
|
||||
});
|
||||
|
||||
it('ahead and behind', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(tempDir, 'a1.txt'), 'Hello World');
|
||||
await git.commit('A1 commit');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(tempDir, 'a2.txt'), 'Hello World');
|
||||
await git.commit('A2 commit');
|
||||
const a2 = await git.getHeadCommitId();
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(tempDir, 'a3.txt'), 'Hello World');
|
||||
await git.commit('A3 commit');
|
||||
const a3 = await git.getHeadCommitId();
|
||||
|
||||
const commits = await git.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(4); // 3 + initial
|
||||
|
||||
const { ahead, behind } = await git.aheadBehind(a2, a3);
|
||||
expect(ahead).toEqual(0);
|
||||
expect(behind).toEqual(1);
|
||||
});
|
||||
|
||||
function simpleProject() {
|
||||
return {
|
||||
name: 'proj',
|
||||
components: [
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'c8451024-fe91-0cbe-b3ad-85d77dd01432',
|
||||
type: 'Text',
|
||||
x: 237,
|
||||
y: 170,
|
||||
parameters: {
|
||||
text: 'original'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
rootNodeId: 'c8451024-fe91-0cbe-b3ad-85d77dd01432',
|
||||
version: '1'
|
||||
};
|
||||
}
|
||||
});
|
||||
105
packages/noodl-editor/tests/git/git-log.spec.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import path from 'path';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
describe('Git log tests', function () {
|
||||
let git: Git;
|
||||
let tempDir: string | undefined;
|
||||
|
||||
beforeEach(async function () {
|
||||
// Logger.log(`[jest-before]: ${expect.getState().currentTestName}`);
|
||||
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('make a few commits and check logs', async function () {
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file1.txt', 'text');
|
||||
await git.setConfigValue('user.name', 'test');
|
||||
await git.setConfigValue('user.email', 'test@test.test');
|
||||
|
||||
await git.commit('add file1.txt');
|
||||
const commit0 = await git.getHeadCommitId();
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file2.txt', 'text');
|
||||
await git.commit('add file2.txt');
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file3.txt', 'text');
|
||||
await git.commit('add file3.txt');
|
||||
const commit2 = await git.getHeadCommitId();
|
||||
|
||||
const commits = await git.getCommitsBetween(commit0, commit2);
|
||||
expect(commits.length).toBe(2);
|
||||
expect(commits[0].message).toEqual('add file3.txt');
|
||||
expect(commits[0].author.name).toEqual('test');
|
||||
expect(commits[0].author.email).toEqual('test@test.test');
|
||||
expect(commits[1].message).toEqual('add file2.txt');
|
||||
});
|
||||
|
||||
it('can get the commits included in a merge', async function () {
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file1.txt', 'text');
|
||||
await git.commit('add file1.txt');
|
||||
|
||||
//create a new brach and do a checkout
|
||||
await git.createAndCheckoutBranch('test-branch');
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file2.txt', 'text');
|
||||
await git.commit('a commit');
|
||||
const commit1Sha = await git.getHeadCommitId();
|
||||
expect(commit1Sha).toBeTruthy();
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file3.txt', 'text');
|
||||
await git.commit('another commit');
|
||||
const commit2Sha = await git.getHeadCommitId();
|
||||
expect(commit1Sha).toBeTruthy();
|
||||
|
||||
await git.checkoutBranch('main');
|
||||
|
||||
const mainHead = await git.getHeadCommitId();
|
||||
const testBranchHead = await git.getHeadCommitOnBranch('test-branch');
|
||||
|
||||
expect(mainHead).toBeTruthy();
|
||||
expect(testBranchHead).toBeTruthy();
|
||||
|
||||
// TODO: The order matters a lot, this will fail in the real test
|
||||
const commits = await git.getCommitsBetween(mainHead, testBranchHead);
|
||||
|
||||
expect(commits.length).toEqual(2);
|
||||
expect(commits[0].message).toEqual('another commit');
|
||||
expect(commits[1].message).toEqual('a commit');
|
||||
});
|
||||
|
||||
it('support .gitignore', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(tempDir, 'test.txt'), 'hello');
|
||||
FileSystem.instance.writeFileSync(path.join(tempDir, '.DS_Store'), 'asdasd');
|
||||
|
||||
const status1 = await git.status();
|
||||
expect(status1.length).toBe(3);
|
||||
expect(status1).toEqual([
|
||||
{ status: 'new', path: '.gitattributes' },
|
||||
{ status: 'new', path: '.gitignore' },
|
||||
{ status: 'new', path: 'test.txt' }
|
||||
]);
|
||||
|
||||
await git.commit('A added file');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(tempDir, '.DS_Store'), 'asd');
|
||||
|
||||
const status2 = await git.status();
|
||||
expect(status2.length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import fs from 'fs';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
async function unzipFileToFolder(zipPath: string, tempDir: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.readFile(zipPath, (err, data) => {
|
||||
if (err) throw err;
|
||||
|
||||
FileSystem.instance.unzipToFolder(tempDir, data, (r) => {
|
||||
if (r.result === 'success') {
|
||||
resolve();
|
||||
} else {
|
||||
reject(r);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Git tests - misc', () => {
|
||||
let tempDir: string;
|
||||
let remoteDir: string;
|
||||
|
||||
beforeEach(async function () {
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
remoteDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
FileSystem.instance.makeDirectorySync(remoteDir);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(remoteDir, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('can merge text example with two branches', async function () {
|
||||
const zipPath = process.cwd() + '/tests/testfs/git-merge-test-1.zip';
|
||||
|
||||
//unzip test project
|
||||
await unzipFileToFolder(zipPath, tempDir);
|
||||
|
||||
const remoteGit = new Git(mergeProject);
|
||||
await remoteGit.initNewRepo(remoteDir, { bare: true });
|
||||
|
||||
const git = new Git(mergeProject);
|
||||
await git.openRepository(tempDir + 'git-merge-test-1');
|
||||
|
||||
await git.addRemote(remoteDir);
|
||||
await git.push();
|
||||
|
||||
await git.checkoutBranch('branch-test');
|
||||
await git.push();
|
||||
|
||||
const branchCommitId = await git.getHeadCommitOnBranch('main');
|
||||
|
||||
const c = await git.getCommitFromId(branchCommitId);
|
||||
expect(c).toBeTruthy();
|
||||
});
|
||||
});
|
||||
363
packages/noodl-editor/tests/git/git-remote-merge.spec.ts
Normal file
@@ -0,0 +1,363 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
async function readTextFile(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
FileSystem.instance.readTextFile(path, (text) => {
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Git remote tests', function () {
|
||||
let localGitA: Git, localGitB: Git;
|
||||
let remoteGit: Git;
|
||||
|
||||
let localDirA: string;
|
||||
let localDirB: string;
|
||||
let remoteDir: string;
|
||||
|
||||
beforeEach(async function () {
|
||||
// console.log(`[jest-before]: ${jasmine.currentTest.fullName}`);
|
||||
|
||||
remoteDir = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirA = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirB = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
|
||||
// Logger.log("remoteDir: " + remoteDir);
|
||||
// Logger.log("localDirA: " + localDirA);
|
||||
// Logger.log("localDirB: " + localDirB);
|
||||
|
||||
FileSystem.instance.makeDirectorySync(localDirA);
|
||||
FileSystem.instance.makeDirectorySync(localDirB);
|
||||
FileSystem.instance.makeDirectorySync(remoteDir);
|
||||
|
||||
localGitA = new Git(mergeProject);
|
||||
localGitB = new Git(mergeProject);
|
||||
remoteGit = new Git(mergeProject);
|
||||
|
||||
//init a bare repository as remote
|
||||
await remoteGit.initNewRepo(remoteDir, { bare: true });
|
||||
|
||||
//init a new local repo and push it to A (mimics how a new project is created)
|
||||
await localGitA.initNewRepo(localDirA);
|
||||
|
||||
// The new version doesnt make a first commit
|
||||
FileSystem.instance.writeFileSync(localDirA + 'initial.txt', 'Hello World');
|
||||
await localGitA.commit('initial commit');
|
||||
|
||||
await localGitA.addRemote(remoteDir);
|
||||
await localGitA.push();
|
||||
|
||||
//and clone the project as B to another directory
|
||||
await localGitB.clone({
|
||||
url: remoteDir,
|
||||
directory: localDirB,
|
||||
onProgress: undefined
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(remoteDir, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirA, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirB, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can pull and merge remote commits', async function () {
|
||||
//create new file on localA
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'localA file');
|
||||
await localGitA.commit('A added file');
|
||||
await localGitA.push();
|
||||
|
||||
//pull it down on localB
|
||||
await localGitB.pull({});
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('localA file');
|
||||
|
||||
//modify it on localA
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'localA mod');
|
||||
await localGitA.commit('A modified file');
|
||||
await localGitA.push();
|
||||
|
||||
//modify it on localB
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'localB mod');
|
||||
await localGitB.commit('B modified file');
|
||||
|
||||
//pull it down
|
||||
await localGitB.pull({});
|
||||
|
||||
//should have been resolved to latest localB modification
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('localB mod');
|
||||
|
||||
const commits = await localGitB.getCommitsCurrentBranch();
|
||||
|
||||
expect(commits.length).toEqual(5);
|
||||
|
||||
expect(commits[0].message).toEqual('Merge origin/main into main');
|
||||
expect(commits[1].message).toEqual('B modified file');
|
||||
expect(commits[2].message).toEqual('A modified file');
|
||||
expect(commits[3].message).toEqual('A added file');
|
||||
expect(commits[4].message).toEqual('initial commit');
|
||||
});
|
||||
|
||||
it('can pull and merge remote commits when a file is added both on remote and locally', async function () {
|
||||
//create new file on localA and push
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'A file in localA');
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, '.DS_Store'), 'asdasd');
|
||||
await localGitA.commit('A added file');
|
||||
await localGitA.push();
|
||||
|
||||
//add it in localB, and then pull
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'A file in localB');
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, '.DS_Store'), '453456');
|
||||
await localGitB.pull({});
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('A file in localB');
|
||||
|
||||
// Check all the commits
|
||||
const commits = await localGitB.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(2);
|
||||
expect(commits[0].message).toBe('A added file');
|
||||
expect(commits[1].message).toBe('initial commit');
|
||||
|
||||
const status = await localGitB.status();
|
||||
expect(status.length).toBe(1);
|
||||
expect(status[0]).toEqual({ status: 'modified', path: 'test.txt' });
|
||||
});
|
||||
|
||||
it('can pull and merge remote commits when a commits and a file is added both on remote and locally', async function () {
|
||||
await localGitB.pull({});
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'b.txt'), 'asdasd');
|
||||
await localGitB.commit('B commit');
|
||||
await localGitB.push();
|
||||
|
||||
//create new file on localA and push
|
||||
await localGitA.pull({});
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'A file in localA');
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, '.DS_Store'), 'asdasd');
|
||||
await localGitA.commit('A added file');
|
||||
await localGitA.push();
|
||||
|
||||
//add it in localB, and then pull
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'A file in localB');
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, '.DS_Store'), '453456');
|
||||
await localGitB.pull({});
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('A file in localB');
|
||||
|
||||
// Check all the commits
|
||||
const commits = await localGitB.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(3);
|
||||
expect(commits[0].message).toBe('A added file');
|
||||
expect(commits[1].message).toBe('B commit');
|
||||
expect(commits[2].message).toBe('initial commit');
|
||||
|
||||
const status = await localGitB.status();
|
||||
expect(status.length).toBe(1);
|
||||
expect(status[0]).toEqual({ status: 'modified', path: 'test.txt' });
|
||||
});
|
||||
|
||||
it('can reset to merge base when remote is not ahead', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'file');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.fetch({});
|
||||
await localGitB.checkoutRemoteBranch('A');
|
||||
|
||||
//B should now have the file
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('file');
|
||||
|
||||
//do a local uncommitted change
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'modified');
|
||||
|
||||
//reset, and verify that it's back to original file
|
||||
await localGitB.resetToMergeBase();
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('file');
|
||||
|
||||
let commits = await localGitB.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(2);
|
||||
|
||||
//do a local committed change
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'modified');
|
||||
await localGitB.commit('modified file');
|
||||
|
||||
commits = await localGitB.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(3);
|
||||
|
||||
//reset, and verify that it's back to original file, and commit is removed
|
||||
await localGitB.resetToMergeBase();
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('file');
|
||||
|
||||
commits = await localGitB.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(2);
|
||||
});
|
||||
|
||||
it('can reset to merge base when remote is ahead', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'file');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.fetch({});
|
||||
await localGitB.checkoutRemoteBranch('A');
|
||||
|
||||
//do a local committed change
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'modified');
|
||||
await localGitB.commit('modified file');
|
||||
|
||||
// TODO: Make sure the history is correct?
|
||||
|
||||
//... plus a local modification
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'test.txt'), 'modified2');
|
||||
|
||||
//localA pushed new commit to remote
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'file2');
|
||||
await localGitA.commit('Another commit');
|
||||
await localGitA.push();
|
||||
|
||||
//localB fetches, but doesn't merge in (doesn't pull)
|
||||
await localGitB.fetch({});
|
||||
|
||||
//B resets, verify that it's back to original file, and commit is removed, and remote didn't get merged in
|
||||
await localGitB.resetToMergeBase();
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('file');
|
||||
|
||||
const commits = await localGitB.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(3);
|
||||
expect(commits[0].isRemoteAhead).toBe(true);
|
||||
|
||||
// Lets just make sure the commits are in the right order
|
||||
expect(commits[0].message).toBe('Another commit');
|
||||
expect(commits[1].message).toBe('A commit');
|
||||
expect(commits[2].message).toBe('initial commit');
|
||||
});
|
||||
|
||||
it('can handle merge with conflicts in project.json', async function () {
|
||||
const localDirA_projectPath = path.join(localDirA, 'project.json');
|
||||
const localDirB_projectPath = path.join(localDirB, 'project.json');
|
||||
|
||||
// Git A
|
||||
// Write a simple project file to localDirA
|
||||
fs.writeFileSync(localDirA_projectPath, JSON.stringify(simpleProject()));
|
||||
|
||||
// We now have 1 file, project.json
|
||||
const statusA1 = await localGitA.status();
|
||||
expect(statusA1.length).toEqual(1);
|
||||
|
||||
// Commit and add remote
|
||||
await localGitA.commit('add project.json');
|
||||
|
||||
// Git B
|
||||
// Do all the changes on Git B without remote
|
||||
await localGitB.clone({ url: remoteDir, directory: localDirB });
|
||||
|
||||
// Write a simple project file with changes to localDirB
|
||||
const modifiedProjectTestBranch = simpleProject();
|
||||
modifiedProjectTestBranch.components[0].graph.roots[0].parameters.text = 'changed';
|
||||
fs.writeFileSync(localDirB_projectPath, JSON.stringify(modifiedProjectTestBranch));
|
||||
|
||||
// We now have 1 file, project.json
|
||||
const statusB1 = await localGitB.status();
|
||||
expect(statusB1.length).toEqual(1);
|
||||
|
||||
// Commit and push to remote
|
||||
await localGitB.commit('commit');
|
||||
|
||||
// Merge
|
||||
await localGitA.push();
|
||||
await localGitB.pull({});
|
||||
await localGitB.push();
|
||||
|
||||
const proj = JSON.parse(await fs.promises.readFile(localDirB_projectPath, 'utf8'));
|
||||
|
||||
const conflicts = proj.components[0].graph.roots[0].conflicts;
|
||||
expect(conflicts.length).toBe(1);
|
||||
expect(conflicts[0].name).toBe('text');
|
||||
expect(conflicts[0].ours).toBe('changed');
|
||||
expect(conflicts[0].theirs).toBe('original');
|
||||
});
|
||||
|
||||
it('Merge with conflicts everywhere, even in stash', async function () {
|
||||
const localDirA_projectPath = path.join(localDirA, 'project.json');
|
||||
const localDirB_projectPath = path.join(localDirB, 'project.json');
|
||||
|
||||
// Git A
|
||||
// Write a simple project file to localDirA
|
||||
fs.writeFileSync(localDirA_projectPath, JSON.stringify(simpleProject()));
|
||||
|
||||
// We now have 1 file, project.json
|
||||
const statusA1 = await localGitA.status();
|
||||
expect(statusA1.length).toEqual(1);
|
||||
|
||||
// Commit and add remote
|
||||
await localGitA.commit('add project.json');
|
||||
|
||||
// Git B
|
||||
// Do all the changes on Git B without remote
|
||||
await localGitB.clone({ url: remoteDir, directory: localDirB });
|
||||
|
||||
// Write a simple project file with changes to localDirB
|
||||
const modifiedProjectTestBranch = simpleProject();
|
||||
modifiedProjectTestBranch.components[0].graph.roots[0].parameters.text = 'changed';
|
||||
fs.writeFileSync(localDirB_projectPath, JSON.stringify(modifiedProjectTestBranch));
|
||||
|
||||
// We now have 1 file, project.json
|
||||
const statusB1 = await localGitB.status();
|
||||
expect(statusB1.length).toEqual(1);
|
||||
|
||||
// Commit and push to remote
|
||||
await localGitB.commit('commit');
|
||||
|
||||
// Write a simple project file with changes to localDirB
|
||||
const modifiedProjectTestBranch2 = simpleProject();
|
||||
modifiedProjectTestBranch2.components[0].graph.roots[0].parameters.text = 'stashed';
|
||||
fs.writeFileSync(localDirB_projectPath, JSON.stringify(modifiedProjectTestBranch2));
|
||||
|
||||
// Merge
|
||||
await localGitA.push();
|
||||
await localGitB.pull({});
|
||||
await localGitB.push();
|
||||
|
||||
const proj = JSON.parse(await fs.promises.readFile(localDirB_projectPath, 'utf8'));
|
||||
|
||||
const entry = proj.components[0].graph.roots[0];
|
||||
expect(entry.parameters.text).toBe('stashed');
|
||||
});
|
||||
});
|
||||
|
||||
function simpleProject() {
|
||||
return {
|
||||
name: 'proj',
|
||||
components: [
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'c8451024-fe91-0cbe-b3ad-85d77dd01432',
|
||||
type: 'Text',
|
||||
x: 237,
|
||||
y: 170,
|
||||
parameters: {
|
||||
text: 'original'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
rootNodeId: 'c8451024-fe91-0cbe-b3ad-85d77dd01432',
|
||||
version: '1'
|
||||
};
|
||||
}
|
||||
122
packages/noodl-editor/tests/git/git-remote-squash.spec.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import path from 'path';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
// jest.setTimeout(10_000);
|
||||
|
||||
async function readTextFile(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
FileSystem.instance.readTextFile(path, (text) => {
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Git remote squash tests', function () {
|
||||
let localGitA: Git, localGitB: Git;
|
||||
let remoteGit: Git;
|
||||
|
||||
let localDirA: string;
|
||||
let localDirB: string;
|
||||
let remoteDir: string;
|
||||
|
||||
beforeEach(async function () {
|
||||
// console.log(`[jest-before]: ${jasmine.currentTest.fullName}`);
|
||||
|
||||
remoteDir = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirA = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirB = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
|
||||
// Logger.log("remoteDir: " + remoteDir);
|
||||
// Logger.log("localDirA: " + localDirA);
|
||||
// Logger.log("localDirB: " + localDirB);
|
||||
|
||||
FileSystem.instance.makeDirectorySync(localDirA);
|
||||
FileSystem.instance.makeDirectorySync(localDirB);
|
||||
FileSystem.instance.makeDirectorySync(remoteDir);
|
||||
|
||||
localGitA = new Git(mergeProject);
|
||||
localGitB = new Git(mergeProject);
|
||||
remoteGit = new Git(mergeProject);
|
||||
|
||||
//init a bare repository as remote
|
||||
await remoteGit.initNewRepo(remoteDir, { bare: true });
|
||||
|
||||
//init a new local repo and push it to A (mimics how a new project is created)
|
||||
await localGitA.initNewRepo(localDirA);
|
||||
|
||||
// The new version doesnt make a first commit
|
||||
FileSystem.instance.writeFileSync(localDirA + 'initial.txt', 'Hello World');
|
||||
await localGitA.commit('initial commit');
|
||||
|
||||
await localGitA.addRemote(remoteDir);
|
||||
await localGitA.push();
|
||||
|
||||
//and clone the project as B to another directory
|
||||
await localGitB.clone({
|
||||
url: remoteDir,
|
||||
directory: localDirB,
|
||||
onProgress: undefined
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(remoteDir, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirA, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirB, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Push when there are remote changes (squash merge)', async function () {
|
||||
await localGitB.createAndCheckoutBranch('squash-test');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'a.txt'), 'Hello World');
|
||||
await localGitB.commit('commit 1');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'b.txt'), 'Hello World');
|
||||
await localGitB.commit('commit 2');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'c.txt'), 'Hello World');
|
||||
await localGitB.commit('commit 3');
|
||||
|
||||
await localGitB.push();
|
||||
|
||||
await localGitA.pull({});
|
||||
await localGitA.mergeToCurrentBranch('origin/squash-test');
|
||||
|
||||
const commits = await localGitA.getCommitsCurrentBranch();
|
||||
expect(commits[0].message).toBe("Squashed commit from branch 'origin/squash-test'");
|
||||
expect(commits[1].message).toBe('initial commit');
|
||||
});
|
||||
|
||||
it('Push when there are remote changes (merge)', async function () {
|
||||
await localGitB.createAndCheckoutBranch('squash-test');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'a.txt'), 'Hello World');
|
||||
await localGitB.commit('commit 1');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'b.txt'), 'Hello World');
|
||||
await localGitB.commit('commit 2');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'c.txt'), 'Hello World');
|
||||
await localGitB.commit('commit 3');
|
||||
|
||||
await localGitB.push();
|
||||
|
||||
await localGitA.pull({});
|
||||
await localGitA.mergeToCurrentBranch('origin/squash-test', false);
|
||||
|
||||
const commits = await localGitA.getCommitsCurrentBranch();
|
||||
expect(commits[0].message).toBe('commit 3');
|
||||
expect(commits[1].message).toBe('commit 2');
|
||||
expect(commits[2].message).toBe('commit 1');
|
||||
expect(commits[3].message).toBe('initial commit');
|
||||
});
|
||||
});
|
||||
325
packages/noodl-editor/tests/git/git-remote.spec.ts
Normal file
@@ -0,0 +1,325 @@
|
||||
import path from 'path';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
// jest.setTimeout(10_000);
|
||||
|
||||
async function readTextFile(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
FileSystem.instance.readTextFile(path, (text) => {
|
||||
resolve(text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('Git remote tests', function () {
|
||||
let localGitA: Git, localGitB: Git;
|
||||
let remoteGit: Git;
|
||||
|
||||
let localDirA: string;
|
||||
let localDirB: string;
|
||||
let remoteDir: string;
|
||||
|
||||
beforeEach(async function () {
|
||||
// console.log(`[jest-before]: ${jasmine.currentTest.fullName}`);
|
||||
|
||||
remoteDir = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirA = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirB = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
|
||||
// Logger.log("remoteDir: " + remoteDir);
|
||||
// Logger.log("localDirA: " + localDirA);
|
||||
// Logger.log("localDirB: " + localDirB);
|
||||
|
||||
FileSystem.instance.makeDirectorySync(localDirA);
|
||||
FileSystem.instance.makeDirectorySync(localDirB);
|
||||
FileSystem.instance.makeDirectorySync(remoteDir);
|
||||
|
||||
localGitA = new Git(mergeProject);
|
||||
localGitB = new Git(mergeProject);
|
||||
remoteGit = new Git(mergeProject);
|
||||
|
||||
//init a bare repository as remote
|
||||
await remoteGit.initNewRepo(remoteDir, { bare: true });
|
||||
|
||||
//init a new local repo and push it to A (mimics how a new project is created)
|
||||
await localGitA.initNewRepo(localDirA);
|
||||
|
||||
// The new version doesnt make a first commit
|
||||
FileSystem.instance.writeFileSync(localDirA + 'initial.txt', 'Hello World');
|
||||
await localGitA.commit('initial commit');
|
||||
|
||||
await localGitA.addRemote(remoteDir);
|
||||
await localGitA.push();
|
||||
|
||||
//and clone the project as B to another directory
|
||||
await localGitB.clone({
|
||||
url: remoteDir,
|
||||
directory: localDirB,
|
||||
onProgress: undefined
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(remoteDir, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirA, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirB, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can get remote head', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('local commit');
|
||||
|
||||
const remoteHeadId1 = await localGitA.getRemoteHeadCommitId();
|
||||
const localHeadId1 = await localGitA.getHeadCommitId();
|
||||
expect(remoteHeadId1).not.toEqual(localHeadId1);
|
||||
|
||||
await localGitA.push();
|
||||
|
||||
const remoteHeadId2 = await localGitA.getRemoteHeadCommitId();
|
||||
const localHeadId2 = await localGitA.getHeadCommitId();
|
||||
expect(remoteHeadId2).toEqual(localHeadId2);
|
||||
});
|
||||
|
||||
it('can push and fetch remote commits', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('localA commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.fetch({});
|
||||
|
||||
const commits = await localGitB.getCommitsCurrentBranch();
|
||||
|
||||
expect(commits[0].isLocalAhead).toBe(false);
|
||||
expect(commits[0].isRemoteAhead).toBe(true);
|
||||
expect(commits[0].message).toEqual('localA commit');
|
||||
|
||||
expect(commits[0].isLocalAhead).toBe(false);
|
||||
expect(commits[1].isRemoteAhead).toBe(false);
|
||||
expect(commits[1].message).toEqual('initial commit');
|
||||
|
||||
expect(commits.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('can list local and remote branches', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
await localGitB.createAndCheckoutBranch('B');
|
||||
|
||||
await localGitA.push();
|
||||
await localGitB.fetch({});
|
||||
|
||||
const branches = await localGitB.getBranches();
|
||||
|
||||
//alphabetical order
|
||||
expect(branches[0]).toEqual({ name: 'A', remote: true, local: false });
|
||||
expect(branches[1]).toEqual({ name: 'B', remote: false, local: true });
|
||||
expect(branches[2]).toEqual({ name: 'main', remote: true, local: true });
|
||||
|
||||
expect(branches.length).toBe(3);
|
||||
});
|
||||
|
||||
it('can checkout remote branch', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'remote file');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.fetch({});
|
||||
await localGitB.checkoutRemoteBranch('A');
|
||||
|
||||
expect(await readTextFile(path.join(localDirB, 'test.txt'))).toBe('remote file');
|
||||
|
||||
const commits = await localGitB.getCommitsCurrentBranch();
|
||||
|
||||
expect(commits[0].message).toEqual('A commit');
|
||||
expect(commits.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('can list remote branch correctly when they have slashes in the name', async function () {
|
||||
await localGitA.createAndCheckoutBranch('test/A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'test.txt'), 'remote file');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.fetch({});
|
||||
const branches = await localGitB.getBranches();
|
||||
|
||||
expect(branches[1]).toEqual({ name: 'test/A', remote: true, local: false });
|
||||
});
|
||||
|
||||
it('can delete remote branch', async function () {
|
||||
//A creates a new branch
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
await localGitA.push();
|
||||
|
||||
//B fetches the new branch
|
||||
await localGitB.fetch({});
|
||||
let branches = await localGitB.getBranches();
|
||||
expect(branches.length).toEqual(2);
|
||||
|
||||
//B deletes the branch
|
||||
await localGitB.deleteRemoteBranch('A');
|
||||
|
||||
//.. and B now doesn't have it anymore
|
||||
branches = await localGitB.getBranches();
|
||||
expect(branches.length).toEqual(1);
|
||||
|
||||
//A should think it still exists on the remote
|
||||
branches = await localGitA.getBranches();
|
||||
expect(branches.find((b) => b.name === 'A').remote).toEqual(true);
|
||||
|
||||
//but after a fetch it should be local only
|
||||
await localGitA.fetch({});
|
||||
branches = await localGitA.getBranches();
|
||||
const branchA = branches.find((b) => b.name === 'A');
|
||||
expect(branchA.remote).toEqual(false);
|
||||
expect(branchA.local).toEqual(true);
|
||||
});
|
||||
|
||||
it('can delete local branch but leave remote intact', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.fetch({});
|
||||
await localGitB.checkoutRemoteBranch('A');
|
||||
|
||||
let branches = await localGitB.getBranches();
|
||||
expect(branches.length).toEqual(2);
|
||||
expect(branches[0]).toEqual({ name: 'A', local: true, remote: true });
|
||||
|
||||
await localGitB.checkoutBranch('main');
|
||||
await localGitB.deleteBranch('A');
|
||||
|
||||
branches = await localGitB.getBranches();
|
||||
expect(branches.length).toEqual(2);
|
||||
|
||||
expect(branches[0]).toEqual({ name: 'A', local: false, remote: true });
|
||||
});
|
||||
|
||||
it('correctly identifies local vs remote commits - one ahead', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('A commit');
|
||||
expect(await localGitA.push()).toBe(true);
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a1.txt'), 'Hello World');
|
||||
await localGitA.commit('A1 commit');
|
||||
|
||||
const commits = await localGitA.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(3);
|
||||
expect(commits[0].isLocalAhead).toBe(true);
|
||||
expect(commits[1].isLocalAhead).toBeFalsy();
|
||||
});
|
||||
|
||||
it('correctly identifies local vs remote commits - branch not pushed', async function () {
|
||||
await localGitA.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('A commit');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a1.txt'), 'Hello World');
|
||||
await localGitA.commit('A1 commit');
|
||||
|
||||
const commits = await localGitA.getCommitsCurrentBranch();
|
||||
expect(commits.length).toBe(3);
|
||||
expect(commits[0].isLocalAhead).toBe(true);
|
||||
expect(commits[1].isLocalAhead).toBe(true);
|
||||
});
|
||||
|
||||
it('Push when there are remote changes', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push({});
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'a.txt'), 'Hello World2');
|
||||
await localGitB.commit('A commit');
|
||||
|
||||
try {
|
||||
await localGitB.push({});
|
||||
expect(true).toBe(false);
|
||||
} catch (error) {
|
||||
expect(error.toString()).toContain(
|
||||
'Updates were rejected because there are new changes that you do not have locally.'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('getCommitsBetween returns the correct commits (squash)', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.pull({});
|
||||
await localGitB.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'b.txt'), 'Hello World');
|
||||
await localGitB.commit('B commit');
|
||||
await localGitB.push();
|
||||
|
||||
const headCommitId = await localGitA.getHeadCommitId();
|
||||
const branchCommitId = await localGitB.getHeadCommitId();
|
||||
|
||||
const allCommits = await localGitA.getCommitsCurrentBranch();
|
||||
expect(allCommits.length).toBe(2);
|
||||
expect(allCommits[0].message).toBe('A commit');
|
||||
expect(allCommits[1].message).toBe('initial commit');
|
||||
|
||||
const commits = await localGitB.getCommitsBetween(branchCommitId, headCommitId);
|
||||
expect(commits.length).toBe(1);
|
||||
expect(commits[0].message).toBe('B commit');
|
||||
|
||||
await localGitA.fetch({});
|
||||
await localGitA.mergeToCurrentBranch('origin/A');
|
||||
|
||||
const allCommits2 = await localGitA.getCommitsCurrentBranch();
|
||||
expect(allCommits2.length).toBe(3);
|
||||
expect(allCommits2[0].message).toBe("Squashed commit from branch 'origin/A'");
|
||||
expect(allCommits2[1].message).toBe('A commit');
|
||||
expect(allCommits2[2].message).toBe('initial commit');
|
||||
});
|
||||
|
||||
it('getCommitsBetween returns the correct commits', async function () {
|
||||
FileSystem.instance.writeFileSync(path.join(localDirA, 'a.txt'), 'Hello World');
|
||||
await localGitA.commit('A commit');
|
||||
await localGitA.push();
|
||||
|
||||
await localGitB.pull({});
|
||||
await localGitB.createAndCheckoutBranch('A');
|
||||
|
||||
FileSystem.instance.writeFileSync(path.join(localDirB, 'b.txt'), 'Hello World');
|
||||
await localGitB.commit('B commit');
|
||||
await localGitB.push();
|
||||
|
||||
const headCommitId = await localGitA.getHeadCommitId();
|
||||
const branchCommitId = await localGitB.getHeadCommitId();
|
||||
|
||||
const allCommits = await localGitA.getCommitsCurrentBranch();
|
||||
expect(allCommits.length).toBe(2);
|
||||
expect(allCommits[0].message).toBe('A commit');
|
||||
expect(allCommits[1].message).toBe('initial commit');
|
||||
|
||||
const commits = await localGitB.getCommitsBetween(branchCommitId, headCommitId);
|
||||
expect(commits.length).toBe(1);
|
||||
expect(commits[0].message).toBe('B commit');
|
||||
|
||||
await localGitA.fetch({});
|
||||
await localGitA.mergeToCurrentBranch('origin/A', false);
|
||||
|
||||
const allCommits2 = await localGitA.getCommitsCurrentBranch();
|
||||
expect(allCommits2.length).toBe(3);
|
||||
expect(allCommits2[0].message).toBe('B commit');
|
||||
expect(allCommits2[1].message).toBe('A commit');
|
||||
expect(allCommits2[2].message).toBe('initial commit');
|
||||
});
|
||||
});
|
||||
107
packages/noodl-editor/tests/git/git-stash-merge.spec.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
describe('Git stash tests', function () {
|
||||
let localGitA: Git, localGitB: Git;
|
||||
let remoteGit: Git;
|
||||
|
||||
let localDirA: string;
|
||||
let localDirB: string;
|
||||
let remoteDir: string;
|
||||
|
||||
beforeEach(async function () {
|
||||
// Logger.log(`[jest-before]: ${expect.getState().currentTestName}`)
|
||||
|
||||
remoteDir = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirA = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
localDirB = path.join(app.getPath('temp'), '/noodlunittests-git-' + Utils.guid());
|
||||
|
||||
// Logger.log("remoteDir: " + remoteDir);
|
||||
// Logger.log("localDirA: " + localDirA);
|
||||
// Logger.log("localDirB: " + localDirB);
|
||||
|
||||
FileSystem.instance.makeDirectorySync(localDirA);
|
||||
FileSystem.instance.makeDirectorySync(localDirB);
|
||||
FileSystem.instance.makeDirectorySync(remoteDir);
|
||||
|
||||
localGitA = new Git(mergeProject);
|
||||
localGitB = new Git(mergeProject);
|
||||
remoteGit = new Git(mergeProject);
|
||||
|
||||
//init a bare repository as remote
|
||||
await remoteGit.initNewRepo(remoteDir, { bare: true });
|
||||
|
||||
//init a new local repo and push it to A (mimics how a new project is created)
|
||||
await localGitA.initNewRepo(localDirA);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`)
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(remoteDir, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirA, () => {
|
||||
FileSystem.instance.removeDirectoryRecursive(localDirB, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Issue: https://app.asana.com/0/1202061493156140/1202351418844106/f
|
||||
* >
|
||||
* > Michael Cartner:
|
||||
* > i mitt fall så var det två användare som öppnade samma 2.5 projekt.
|
||||
* > Båda skapade då en .gitignore lokalt
|
||||
* > Användare A commitade
|
||||
* > Användare B pullade => felmeddelandet ovan
|
||||
* >
|
||||
* >
|
||||
* > Related?: https://stackoverflow.com/questions/51275777/why-does-git-stash-pop-say-that-it-could-not-restore-untracked-files-from-stash
|
||||
*/
|
||||
it('pop-stash with merge issues', async function () {
|
||||
// Git A
|
||||
// 1. delete .gitignore
|
||||
const statusA1 = await localGitA.status();
|
||||
expect(statusA1.length).toEqual(2); // .gitignore and .gitattributes
|
||||
|
||||
fs.writeFileSync(localDirA + '/temp', 'temp');
|
||||
fs.unlinkSync(localDirA + '/.gitignore');
|
||||
|
||||
await localGitA.commit('initial commit without .gitignore');
|
||||
await localGitA.addRemote(remoteDir);
|
||||
await localGitA.push();
|
||||
|
||||
// Git B
|
||||
await localGitB.clone({ url: remoteDir, directory: localDirB });
|
||||
await localGitB.fetch({});
|
||||
|
||||
const statusB1 = await localGitB.status();
|
||||
expect(statusB1.length).toEqual(1);
|
||||
|
||||
await localGitB.commit('commit .gitignore');
|
||||
await localGitB.push();
|
||||
|
||||
// Git A
|
||||
// Recreate the repo (creating .gitignore)
|
||||
localGitA = new Git(mergeProject);
|
||||
await localGitA.openRepository(localDirA);
|
||||
|
||||
// Check that we have it
|
||||
const statusA2 = await localGitA.status();
|
||||
expect(statusA2.length).toEqual(1);
|
||||
|
||||
/**
|
||||
* GitError: .gitignore already exists, no checkout
|
||||
* error: could not restore untracked files from stash
|
||||
*/
|
||||
await localGitA.pull({});
|
||||
|
||||
const statusA3 = await localGitA.status();
|
||||
expect(statusA3.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
51
packages/noodl-editor/tests/git/git-stash.spec.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
describe('Git stash tests', function () {
|
||||
let git: Git;
|
||||
let tempDir: string | undefined;
|
||||
|
||||
beforeEach(async function () {
|
||||
// Logger.log(`[jest-before]: ${expect.getState().currentTestName}`)
|
||||
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
// Logger.log(`\r\n[jest-after]: ${expect.getState().currentTestName}`)
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('stash changes', async function () {
|
||||
// cant stash when there are no commits
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file.txt', 'text');
|
||||
await git.commit('initial commit');
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file1.txt', 'text');
|
||||
expect(await git.stashPushChanges()).toBeTruthy();
|
||||
|
||||
const status1 = await git.status();
|
||||
expect(status1).toEqual([]);
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file2.txt', 'text');
|
||||
expect(await git.stashPopChanges()).toBe(true);
|
||||
|
||||
// NOTE: Got some issue on OSX where pop was called using spawn process.
|
||||
// OSX didn't seem to like this and ignored the call, changed it to exec.
|
||||
|
||||
// Calling pop here again makes sure that the previous pop worked.
|
||||
expect(await git.stashPopChanges()).toBe(false);
|
||||
|
||||
const status2 = await git.status();
|
||||
expect(status2.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
76
packages/noodl-editor/tests/git/git-status.spec.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { app } from '@electron/remote';
|
||||
import { Git } from '@noodl/git';
|
||||
|
||||
import FileSystem from '@noodl-utils/filesystem';
|
||||
import { mergeProject } from '@noodl-utils/projectmerger';
|
||||
import Utils from '@noodl-utils/utils';
|
||||
|
||||
describe('Git status tests', function () {
|
||||
let git: Git;
|
||||
let tempDir: string | undefined;
|
||||
|
||||
beforeEach(async function () {
|
||||
tempDir = app.getPath('temp') + '/noodlunittests-git-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
git = new Git(mergeProject);
|
||||
await git.initNewRepo(tempDir);
|
||||
});
|
||||
|
||||
afterEach(function (done) {
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, done);
|
||||
tempDir = undefined;
|
||||
});
|
||||
|
||||
it('create file', async function () {
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file.txt', 'text');
|
||||
const status = await git.status();
|
||||
|
||||
expect(status).toEqual([
|
||||
{
|
||||
status: 'new',
|
||||
path: '.gitattributes'
|
||||
},
|
||||
{
|
||||
status: 'new',
|
||||
path: '.gitignore'
|
||||
},
|
||||
{
|
||||
status: 'new',
|
||||
path: 'file.txt'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('create file, commit and update file', async function () {
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file.txt', 'text');
|
||||
|
||||
const status1 = await git.status();
|
||||
expect(status1).toEqual([
|
||||
{
|
||||
status: 'new',
|
||||
path: '.gitattributes'
|
||||
},
|
||||
{
|
||||
status: 'new',
|
||||
path: '.gitignore'
|
||||
},
|
||||
{
|
||||
status: 'new',
|
||||
path: 'file.txt'
|
||||
}
|
||||
]);
|
||||
|
||||
await git.commit('add file.txt');
|
||||
|
||||
FileSystem.instance.writeFileSync(tempDir + 'file.txt', 'text2');
|
||||
|
||||
const status2 = await git.status();
|
||||
expect(status2).toEqual([
|
||||
{
|
||||
status: 'modified',
|
||||
path: 'file.txt'
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
13
packages/noodl-editor/tests/git/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export * from './git-diff.spec';
|
||||
export * from './git-local.spec';
|
||||
export * from './git-local-merge.spec';
|
||||
export * from './git-real-project-tests.spec';
|
||||
export * from './git-log.spec';
|
||||
export * from './git-clone-and-fetch-remote.spec';
|
||||
export * from './git-remote-merge.spec';
|
||||
export * from './git-remote-squash.spec';
|
||||
export * from './git-remote.spec';
|
||||
export * from './git-stash-merge.spec';
|
||||
export * from './git-stash.spec';
|
||||
export * from './git-status.spec';
|
||||
export * from './git-local-misc.spec';
|
||||
13
packages/noodl-editor/tests/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// Setup the platform before anything else is loading
|
||||
// This is a problem since we are calling the platform when importing
|
||||
import '@noodl/platform-electron';
|
||||
|
||||
export * from './cloud';
|
||||
export * from './components';
|
||||
export * from './git';
|
||||
export * from './nodegraph';
|
||||
export * from './platform';
|
||||
export * from './project';
|
||||
export * from './projectmerger';
|
||||
export * from './projectpatcher';
|
||||
export * from './utils';
|
||||
152
packages/noodl-editor/tests/lib/jasmine-3.7.1/boot.js
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
|
||||
|
||||
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
|
||||
|
||||
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
|
||||
|
||||
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
|
||||
*/
|
||||
|
||||
(function () {
|
||||
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
|
||||
|
||||
/**
|
||||
* ## Require & Instantiate
|
||||
*
|
||||
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
|
||||
*/
|
||||
var jasmine = jasmineRequire.core(jasmineRequire),
|
||||
global = jasmine.getGlobal();
|
||||
global.jasmine = jasmine;
|
||||
|
||||
/**
|
||||
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
|
||||
*/
|
||||
jasmineRequire.html(jasmine);
|
||||
|
||||
/**
|
||||
* Create the Jasmine environment. This is used to run all specs in a project.
|
||||
*/
|
||||
var env = jasmine.getEnv();
|
||||
|
||||
/**
|
||||
* ## The Global Interface
|
||||
*
|
||||
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
|
||||
*/
|
||||
var jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||
|
||||
/**
|
||||
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
|
||||
*/
|
||||
extend(global, jasmineInterface);
|
||||
|
||||
/**
|
||||
* ## Runner Parameters
|
||||
*
|
||||
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
|
||||
*/
|
||||
|
||||
var queryString = new jasmine.QueryString({
|
||||
getWindowLocation: function () {
|
||||
return window.location;
|
||||
}
|
||||
});
|
||||
|
||||
var filterSpecs = !!queryString.getParam('spec');
|
||||
|
||||
var config = {
|
||||
failFast: queryString.getParam('failFast'),
|
||||
oneFailurePerSpec: queryString.getParam('oneFailurePerSpec'),
|
||||
hideDisabled: queryString.getParam('hideDisabled')
|
||||
};
|
||||
|
||||
var random = queryString.getParam('random');
|
||||
|
||||
if (random !== undefined && random !== '') {
|
||||
config.random = random;
|
||||
}
|
||||
|
||||
var seed = queryString.getParam('seed');
|
||||
if (seed) {
|
||||
config.seed = seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Reporters
|
||||
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||
*/
|
||||
var htmlReporter = new jasmine.HtmlReporter({
|
||||
env: env,
|
||||
navigateWithNewParam: function (key, value) {
|
||||
return queryString.navigateWithNewParam(key, value);
|
||||
},
|
||||
addToExistingQueryString: function (key, value) {
|
||||
return queryString.fullStringWithNewParam(key, value);
|
||||
},
|
||||
getContainer: function () {
|
||||
return document.body;
|
||||
},
|
||||
createElement: function () {
|
||||
return document.createElement.apply(document, arguments);
|
||||
},
|
||||
createTextNode: function () {
|
||||
return document.createTextNode.apply(document, arguments);
|
||||
},
|
||||
timer: new jasmine.Timer(),
|
||||
filterSpecs: filterSpecs
|
||||
});
|
||||
|
||||
/**
|
||||
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
|
||||
*/
|
||||
env.addReporter(jasmineInterface.jsApiReporter);
|
||||
env.addReporter(htmlReporter);
|
||||
|
||||
/**
|
||||
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
|
||||
*/
|
||||
var specFilter = new jasmine.HtmlSpecFilter({
|
||||
filterString: function () {
|
||||
return queryString.getParam('spec');
|
||||
}
|
||||
});
|
||||
|
||||
config.specFilter = function (spec) {
|
||||
return specFilter.matches(spec.getFullName());
|
||||
};
|
||||
|
||||
env.configure(config);
|
||||
|
||||
/**
|
||||
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
|
||||
*/
|
||||
window.setTimeout = window.setTimeout;
|
||||
window.setInterval = window.setInterval;
|
||||
window.clearTimeout = window.clearTimeout;
|
||||
window.clearInterval = window.clearInterval;
|
||||
|
||||
/**
|
||||
* ## Execution
|
||||
*
|
||||
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
||||
*/
|
||||
var currentWindowOnload = window.onload;
|
||||
|
||||
window.onload = function () {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
}
|
||||
htmlReporter.initialize();
|
||||
env.execute();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function for readability above.
|
||||
*/
|
||||
function extend(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
})();
|
||||
719
packages/noodl-editor/tests/lib/jasmine-3.7.1/jasmine-html.js
vendored
Normal file
@@ -0,0 +1,719 @@
|
||||
/*
|
||||
Copyright (c) 2008-2021 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
|
||||
|
||||
jasmineRequire.html = function (j$) {
|
||||
j$.ResultsNode = jasmineRequire.ResultsNode();
|
||||
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
||||
j$.QueryString = jasmineRequire.QueryString();
|
||||
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
|
||||
};
|
||||
|
||||
jasmineRequire.HtmlReporter = function (j$) {
|
||||
function ResultsStateBuilder() {
|
||||
this.topResults = new j$.ResultsNode({}, '', null);
|
||||
this.currentParent = this.topResults;
|
||||
this.specsExecuted = 0;
|
||||
this.failureCount = 0;
|
||||
this.pendingSpecCount = 0;
|
||||
}
|
||||
|
||||
ResultsStateBuilder.prototype.suiteStarted = function (result) {
|
||||
this.currentParent.addChild(result, 'suite');
|
||||
this.currentParent = this.currentParent.last();
|
||||
};
|
||||
|
||||
ResultsStateBuilder.prototype.suiteDone = function (result) {
|
||||
this.currentParent.updateResult(result);
|
||||
if (this.currentParent !== this.topResults) {
|
||||
this.currentParent = this.currentParent.parent;
|
||||
}
|
||||
|
||||
if (result.status === 'failed') {
|
||||
this.failureCount++;
|
||||
}
|
||||
};
|
||||
|
||||
ResultsStateBuilder.prototype.specStarted = function (result) {};
|
||||
|
||||
ResultsStateBuilder.prototype.specDone = function (result) {
|
||||
this.currentParent.addChild(result, 'spec');
|
||||
|
||||
if (result.status !== 'excluded') {
|
||||
this.specsExecuted++;
|
||||
}
|
||||
|
||||
if (result.status === 'failed') {
|
||||
this.failureCount++;
|
||||
}
|
||||
|
||||
if (result.status == 'pending') {
|
||||
this.pendingSpecCount++;
|
||||
}
|
||||
};
|
||||
|
||||
function HtmlReporter(options) {
|
||||
var config = function () {
|
||||
return (options.env && options.env.configuration()) || {};
|
||||
},
|
||||
getContainer = options.getContainer,
|
||||
createElement = options.createElement,
|
||||
createTextNode = options.createTextNode,
|
||||
navigateWithNewParam = options.navigateWithNewParam || function () {},
|
||||
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
|
||||
filterSpecs = options.filterSpecs,
|
||||
htmlReporterMain,
|
||||
symbols,
|
||||
deprecationWarnings = [];
|
||||
|
||||
this.initialize = function () {
|
||||
clearPrior();
|
||||
htmlReporterMain = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine_html-reporter' },
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-banner' },
|
||||
createDom('a', {
|
||||
className: 'jasmine-title',
|
||||
href: 'http://jasmine.github.io/',
|
||||
target: '_blank'
|
||||
}),
|
||||
createDom('span', { className: 'jasmine-version' }, j$.version)
|
||||
),
|
||||
createDom('ul', { className: 'jasmine-symbol-summary' }),
|
||||
createDom('div', { className: 'jasmine-alert' }),
|
||||
createDom('div', { className: 'jasmine-results' }, createDom('div', { className: 'jasmine-failures' }))
|
||||
);
|
||||
getContainer().appendChild(htmlReporterMain);
|
||||
};
|
||||
|
||||
var totalSpecsDefined;
|
||||
this.jasmineStarted = function (options) {
|
||||
totalSpecsDefined = options.totalSpecsDefined || 0;
|
||||
};
|
||||
|
||||
var summary = createDom('div', { className: 'jasmine-summary' });
|
||||
|
||||
var stateBuilder = new ResultsStateBuilder();
|
||||
|
||||
this.suiteStarted = function (result) {
|
||||
stateBuilder.suiteStarted(result);
|
||||
};
|
||||
|
||||
this.suiteDone = function (result) {
|
||||
stateBuilder.suiteDone(result);
|
||||
|
||||
if (result.status === 'failed') {
|
||||
failures.push(failureDom(result));
|
||||
}
|
||||
addDeprecationWarnings(result, 'suite');
|
||||
};
|
||||
|
||||
this.specStarted = function (result) {
|
||||
stateBuilder.specStarted(result);
|
||||
};
|
||||
|
||||
var failures = [];
|
||||
this.specDone = function (result) {
|
||||
stateBuilder.specDone(result);
|
||||
|
||||
if (noExpectations(result)) {
|
||||
var noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
|
||||
if (result.status === 'failed') {
|
||||
console.error(noSpecMsg);
|
||||
} else {
|
||||
console.warn(noSpecMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!symbols) {
|
||||
symbols = find('.jasmine-symbol-summary');
|
||||
}
|
||||
|
||||
symbols.appendChild(
|
||||
createDom('li', {
|
||||
className: this.displaySpecInCorrectFormat(result),
|
||||
id: 'spec_' + result.id,
|
||||
title: result.fullName
|
||||
})
|
||||
);
|
||||
|
||||
if (result.status === 'failed') {
|
||||
failures.push(failureDom(result));
|
||||
}
|
||||
|
||||
addDeprecationWarnings(result, 'spec');
|
||||
};
|
||||
|
||||
this.displaySpecInCorrectFormat = function (result) {
|
||||
return noExpectations(result) && result.status === 'passed' ? 'jasmine-empty' : this.resultStatus(result.status);
|
||||
};
|
||||
|
||||
this.resultStatus = function (status) {
|
||||
if (status === 'excluded') {
|
||||
return config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
|
||||
}
|
||||
return 'jasmine-' + status;
|
||||
};
|
||||
|
||||
this.jasmineDone = function (doneResult) {
|
||||
var banner = find('.jasmine-banner');
|
||||
var alert = find('.jasmine-alert');
|
||||
var order = doneResult && doneResult.order;
|
||||
var i;
|
||||
alert.appendChild(
|
||||
createDom('span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's')
|
||||
);
|
||||
|
||||
banner.appendChild(optionsMenu(config()));
|
||||
|
||||
if (stateBuilder.specsExecuted < totalSpecsDefined) {
|
||||
var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
|
||||
var skippedLink = addToExistingQueryString('spec', '');
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-bar jasmine-skipped' },
|
||||
createDom('a', { href: skippedLink, title: 'Run all specs' }, skippedMessage)
|
||||
)
|
||||
);
|
||||
}
|
||||
var statusBarMessage = '';
|
||||
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
|
||||
var globalFailures = (doneResult && doneResult.failedExpectations) || [];
|
||||
var failed = stateBuilder.failureCount + globalFailures.length > 0;
|
||||
|
||||
if (totalSpecsDefined > 0 || failed) {
|
||||
statusBarMessage +=
|
||||
pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount);
|
||||
if (stateBuilder.pendingSpecCount) {
|
||||
statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (doneResult.overallStatus === 'passed') {
|
||||
statusBarClassName += ' jasmine-passed ';
|
||||
} else if (doneResult.overallStatus === 'incomplete') {
|
||||
statusBarClassName += ' jasmine-incomplete ';
|
||||
statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage;
|
||||
} else {
|
||||
statusBarClassName += ' jasmine-failed ';
|
||||
}
|
||||
|
||||
var seedBar;
|
||||
if (order && order.random) {
|
||||
seedBar = createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-seed-bar' },
|
||||
', randomized with seed ',
|
||||
createDom(
|
||||
'a',
|
||||
{
|
||||
title: 'randomized with seed ' + order.seed,
|
||||
href: seedHref(order.seed)
|
||||
},
|
||||
order.seed
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
alert.appendChild(createDom('span', { className: statusBarClassName }, statusBarMessage, seedBar));
|
||||
|
||||
var errorBarClassName = 'jasmine-bar jasmine-errored';
|
||||
var afterAllMessagePrefix = 'AfterAll ';
|
||||
|
||||
for (i = 0; i < globalFailures.length; i++) {
|
||||
alert.appendChild(createDom('span', { className: errorBarClassName }, globalFailureMessage(globalFailures[i])));
|
||||
}
|
||||
|
||||
function globalFailureMessage(failure) {
|
||||
if (failure.globalErrorType === 'load') {
|
||||
var prefix = 'Error during loading: ' + failure.message;
|
||||
|
||||
if (failure.filename) {
|
||||
return prefix + ' in ' + failure.filename + ' line ' + failure.lineno;
|
||||
} else {
|
||||
return prefix;
|
||||
}
|
||||
} else {
|
||||
return afterAllMessagePrefix + failure.message;
|
||||
}
|
||||
}
|
||||
|
||||
addDeprecationWarnings(doneResult);
|
||||
|
||||
for (i = 0; i < deprecationWarnings.length; i++) {
|
||||
var context;
|
||||
|
||||
switch (deprecationWarnings[i].runnableType) {
|
||||
case 'spec':
|
||||
context = '(in spec: ' + deprecationWarnings[i].runnableName + ')';
|
||||
break;
|
||||
case 'suite':
|
||||
context = '(in suite: ' + deprecationWarnings[i].runnableName + ')';
|
||||
break;
|
||||
default:
|
||||
context = '';
|
||||
}
|
||||
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-bar jasmine-warning' },
|
||||
'DEPRECATION: ' + deprecationWarnings[i].message,
|
||||
createDom('br'),
|
||||
context
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
var results = find('.jasmine-results');
|
||||
results.appendChild(summary);
|
||||
|
||||
summaryList(stateBuilder.topResults, summary);
|
||||
|
||||
if (failures.length) {
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||
createDom('span', {}, 'Spec List | '),
|
||||
createDom('a', { className: 'jasmine-failures-menu', href: '#' }, 'Failures')
|
||||
)
|
||||
);
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||
createDom('a', { className: 'jasmine-spec-list-menu', href: '#' }, 'Spec List'),
|
||||
createDom('span', {}, ' | Failures ')
|
||||
)
|
||||
);
|
||||
|
||||
find('.jasmine-failures-menu').onclick = function () {
|
||||
setMenuModeTo('jasmine-failure-list');
|
||||
return false;
|
||||
};
|
||||
find('.jasmine-spec-list-menu').onclick = function () {
|
||||
setMenuModeTo('jasmine-spec-list');
|
||||
return false;
|
||||
};
|
||||
|
||||
setMenuModeTo('jasmine-failure-list');
|
||||
|
||||
var failureNode = find('.jasmine-failures');
|
||||
for (i = 0; i < failures.length; i++) {
|
||||
failureNode.appendChild(failures[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function failureDom(result) {
|
||||
var failure = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-spec-detail jasmine-failed' },
|
||||
failureDescription(result, stateBuilder.currentParent),
|
||||
createDom('div', { className: 'jasmine-messages' })
|
||||
);
|
||||
var messages = failure.childNodes[1];
|
||||
|
||||
for (var i = 0; i < result.failedExpectations.length; i++) {
|
||||
var expectation = result.failedExpectations[i];
|
||||
messages.appendChild(createDom('div', { className: 'jasmine-result-message' }, expectation.message));
|
||||
messages.appendChild(createDom('div', { className: 'jasmine-stack-trace' }, expectation.stack));
|
||||
}
|
||||
|
||||
if (result.failedExpectations.length === 0) {
|
||||
messages.appendChild(createDom('div', { className: 'jasmine-result-message' }, 'Spec has no expectations'));
|
||||
}
|
||||
|
||||
return failure;
|
||||
}
|
||||
|
||||
function summaryList(resultsTree, domParent) {
|
||||
var specListNode;
|
||||
for (var i = 0; i < resultsTree.children.length; i++) {
|
||||
var resultNode = resultsTree.children[i];
|
||||
if (filterSpecs && !hasActiveSpec(resultNode)) {
|
||||
continue;
|
||||
}
|
||||
if (resultNode.type === 'suite') {
|
||||
var suiteListNode = createDom(
|
||||
'ul',
|
||||
{ className: 'jasmine-suite', id: 'suite-' + resultNode.result.id },
|
||||
createDom(
|
||||
'li',
|
||||
{
|
||||
className: 'jasmine-suite-detail jasmine-' + resultNode.result.status
|
||||
},
|
||||
createDom('a', { href: specHref(resultNode.result) }, resultNode.result.description)
|
||||
)
|
||||
);
|
||||
|
||||
summaryList(resultNode, suiteListNode);
|
||||
domParent.appendChild(suiteListNode);
|
||||
}
|
||||
if (resultNode.type === 'spec') {
|
||||
if (domParent.getAttribute('class') !== 'jasmine-specs') {
|
||||
specListNode = createDom('ul', { className: 'jasmine-specs' });
|
||||
domParent.appendChild(specListNode);
|
||||
}
|
||||
var specDescription = resultNode.result.description;
|
||||
if (noExpectations(resultNode.result)) {
|
||||
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||
}
|
||||
if (resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '') {
|
||||
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
|
||||
}
|
||||
specListNode.appendChild(
|
||||
createDom(
|
||||
'li',
|
||||
{
|
||||
className: 'jasmine-' + resultNode.result.status,
|
||||
id: 'spec-' + resultNode.result.id
|
||||
},
|
||||
createDom('a', { href: specHref(resultNode.result) }, specDescription)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function optionsMenu(config) {
|
||||
var optionsMenuDom = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-run-options' },
|
||||
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-payload' },
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-stop-on-failure' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-fail-fast',
|
||||
id: 'jasmine-fail-fast',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom(
|
||||
'label',
|
||||
{ className: 'jasmine-label', for: 'jasmine-fail-fast' },
|
||||
'stop execution on spec failure'
|
||||
)
|
||||
),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-throw-failures' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-throw',
|
||||
id: 'jasmine-throw-failures',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom(
|
||||
'label',
|
||||
{ className: 'jasmine-label', for: 'jasmine-throw-failures' },
|
||||
'stop spec on expectation failure'
|
||||
)
|
||||
),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-random-order' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-random',
|
||||
id: 'jasmine-random-order',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom('label', { className: 'jasmine-label', for: 'jasmine-random-order' }, 'run tests in random order')
|
||||
),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-hide-disabled' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-disabled',
|
||||
id: 'jasmine-hide-disabled',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom('label', { className: 'jasmine-label', for: 'jasmine-hide-disabled' }, 'hide disabled tests')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
|
||||
failFastCheckbox.checked = config.failFast;
|
||||
failFastCheckbox.onclick = function () {
|
||||
navigateWithNewParam('failFast', !config.failFast);
|
||||
};
|
||||
|
||||
var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
|
||||
throwCheckbox.checked = config.oneFailurePerSpec;
|
||||
throwCheckbox.onclick = function () {
|
||||
navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
|
||||
};
|
||||
|
||||
var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order');
|
||||
randomCheckbox.checked = config.random;
|
||||
randomCheckbox.onclick = function () {
|
||||
navigateWithNewParam('random', !config.random);
|
||||
};
|
||||
|
||||
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
|
||||
hideDisabled.checked = config.hideDisabled;
|
||||
hideDisabled.onclick = function () {
|
||||
navigateWithNewParam('hideDisabled', !config.hideDisabled);
|
||||
};
|
||||
|
||||
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
|
||||
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
|
||||
isOpen = /\bjasmine-open\b/;
|
||||
|
||||
optionsTrigger.onclick = function () {
|
||||
if (isOpen.test(optionsPayload.className)) {
|
||||
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
|
||||
} else {
|
||||
optionsPayload.className += ' jasmine-open';
|
||||
}
|
||||
};
|
||||
|
||||
return optionsMenuDom;
|
||||
}
|
||||
|
||||
function failureDescription(result, suite) {
|
||||
var wrapper = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-description' },
|
||||
createDom('a', { title: result.description, href: specHref(result) }, result.description)
|
||||
);
|
||||
var suiteLink;
|
||||
|
||||
while (suite && suite.parent) {
|
||||
wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
|
||||
suiteLink = createDom('a', { href: suiteHref(suite) }, suite.result.description);
|
||||
wrapper.insertBefore(suiteLink, wrapper.firstChild);
|
||||
|
||||
suite = suite.parent;
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function suiteHref(suite) {
|
||||
var els = [];
|
||||
|
||||
while (suite && suite.parent) {
|
||||
els.unshift(suite.result.description);
|
||||
suite = suite.parent;
|
||||
}
|
||||
|
||||
return addToExistingQueryString('spec', els.join(' '));
|
||||
}
|
||||
|
||||
function addDeprecationWarnings(result, runnableType) {
|
||||
if (result && result.deprecationWarnings) {
|
||||
for (var i = 0; i < result.deprecationWarnings.length; i++) {
|
||||
var warning = result.deprecationWarnings[i].message;
|
||||
if (!j$.util.arrayContains(warning)) {
|
||||
deprecationWarnings.push({
|
||||
message: warning,
|
||||
runnableName: result.fullName,
|
||||
runnableType: runnableType
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function find(selector) {
|
||||
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
|
||||
}
|
||||
|
||||
function clearPrior() {
|
||||
// return the reporter
|
||||
var oldReporter = find('');
|
||||
|
||||
if (oldReporter) {
|
||||
getContainer().removeChild(oldReporter);
|
||||
}
|
||||
}
|
||||
|
||||
function createDom(type, attrs, childrenVarArgs) {
|
||||
var el = createElement(type);
|
||||
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i];
|
||||
|
||||
if (typeof child === 'string') {
|
||||
el.appendChild(createTextNode(child));
|
||||
} else {
|
||||
if (child) {
|
||||
el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var attr in attrs) {
|
||||
if (attr == 'className') {
|
||||
el[attr] = attrs[attr];
|
||||
} else {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
function pluralize(singular, count) {
|
||||
var word = count == 1 ? singular : singular + 's';
|
||||
|
||||
return '' + count + ' ' + word;
|
||||
}
|
||||
|
||||
function specHref(result) {
|
||||
return addToExistingQueryString('spec', result.fullName);
|
||||
}
|
||||
|
||||
function seedHref(seed) {
|
||||
return addToExistingQueryString('seed', seed);
|
||||
}
|
||||
|
||||
function defaultQueryString(key, value) {
|
||||
return '?' + key + '=' + value;
|
||||
}
|
||||
|
||||
function setMenuModeTo(mode) {
|
||||
htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
|
||||
}
|
||||
|
||||
function noExpectations(result) {
|
||||
var allExpectations = result.failedExpectations.length + result.passedExpectations.length;
|
||||
|
||||
return allExpectations === 0 && (result.status === 'passed' || result.status === 'failed');
|
||||
}
|
||||
|
||||
function hasActiveSpec(resultNode) {
|
||||
if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (resultNode.type == 'suite') {
|
||||
for (var i = 0, j = resultNode.children.length; i < j; i++) {
|
||||
if (hasActiveSpec(resultNode.children[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return HtmlReporter;
|
||||
};
|
||||
|
||||
jasmineRequire.HtmlSpecFilter = function () {
|
||||
function HtmlSpecFilter(options) {
|
||||
var filterString =
|
||||
options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
var filterPattern = new RegExp(filterString);
|
||||
|
||||
this.matches = function (specName) {
|
||||
return filterPattern.test(specName);
|
||||
};
|
||||
}
|
||||
|
||||
return HtmlSpecFilter;
|
||||
};
|
||||
|
||||
jasmineRequire.ResultsNode = function () {
|
||||
function ResultsNode(result, type, parent) {
|
||||
this.result = result;
|
||||
this.type = type;
|
||||
this.parent = parent;
|
||||
|
||||
this.children = [];
|
||||
|
||||
this.addChild = function (result, type) {
|
||||
this.children.push(new ResultsNode(result, type, this));
|
||||
};
|
||||
|
||||
this.last = function () {
|
||||
return this.children[this.children.length - 1];
|
||||
};
|
||||
|
||||
this.updateResult = function (result) {
|
||||
this.result = result;
|
||||
};
|
||||
}
|
||||
|
||||
return ResultsNode;
|
||||
};
|
||||
|
||||
jasmineRequire.QueryString = function () {
|
||||
function QueryString(options) {
|
||||
this.navigateWithNewParam = function (key, value) {
|
||||
options.getWindowLocation().search = this.fullStringWithNewParam(key, value);
|
||||
};
|
||||
|
||||
this.fullStringWithNewParam = function (key, value) {
|
||||
var paramMap = queryStringToParamMap();
|
||||
paramMap[key] = value;
|
||||
return toQueryString(paramMap);
|
||||
};
|
||||
|
||||
this.getParam = function (key) {
|
||||
return queryStringToParamMap()[key];
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function toQueryString(paramMap) {
|
||||
var qStrPairs = [];
|
||||
for (var prop in paramMap) {
|
||||
qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]));
|
||||
}
|
||||
return '?' + qStrPairs.join('&');
|
||||
}
|
||||
|
||||
function queryStringToParamMap() {
|
||||
var paramStr = options.getWindowLocation().search.substring(1),
|
||||
params = [],
|
||||
paramMap = {};
|
||||
|
||||
if (paramStr.length > 0) {
|
||||
params = paramStr.split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
var value = decodeURIComponent(p[1]);
|
||||
if (value === 'true' || value === 'false') {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
paramMap[decodeURIComponent(p[0])] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return paramMap;
|
||||
}
|
||||
}
|
||||
|
||||
return QueryString;
|
||||
};
|
||||
128
packages/noodl-editor/tests/lib/jasmine-3.7.1/jasmine.css
vendored
Normal file
8802
packages/noodl-editor/tests/lib/jasmine-3.7.1/jasmine.js
vendored
Normal file
BIN
packages/noodl-editor/tests/lib/jasmine-3.7.1/jasmine_favicon.png
vendored
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
178
packages/noodl-editor/tests/nodegraph/conflictwarnings.js
Normal file
@@ -0,0 +1,178 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const WarningsModel = require('@noodl-models/warningsmodel').WarningsModel;
|
||||
|
||||
describe('Conflict warnings', function () {
|
||||
var p;
|
||||
|
||||
beforeEach(() => {
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
|
||||
p = ProjectModel.fromJSON(getProject());
|
||||
ProjectModel.instance = p;
|
||||
});
|
||||
|
||||
it('can load project', function () {
|
||||
expect(p).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can count total number of conflicts', function () {
|
||||
p.getComponentWithName('comp1').graph.evaluateHealth();
|
||||
p.getComponentWithName('comp2').graph.evaluateHealth();
|
||||
p.getComponentWithName('comp3').graph.evaluateHealth();
|
||||
|
||||
expect(
|
||||
WarningsModel.instance.getTotalNumberOfWarningsMatching(
|
||||
(key, ref, warning) => warning.warning.type === 'conflict'
|
||||
)
|
||||
).toBe(4);
|
||||
});
|
||||
|
||||
it('can count warnings for a components', function () {
|
||||
const c = p.getComponentWithName('comp1');
|
||||
c.graph.evaluateHealth();
|
||||
let warnings = WarningsModel.instance.getNumberOfWarningsForComponent(c);
|
||||
expect(warnings).toBe(1);
|
||||
|
||||
//conflict warnings are global, so test counting all non-global conflicts as well
|
||||
warnings = WarningsModel.instance.getNumberOfWarningsForComponent(c, {
|
||||
excludeGlobal: true
|
||||
});
|
||||
expect(warnings).toBe(0);
|
||||
});
|
||||
|
||||
it('can detect param conflict warnings', function () {
|
||||
var c = p.getComponentWithName('comp1');
|
||||
c.graph.evaluateHealth();
|
||||
|
||||
var w = WarningsModel.instance.warnings['comp1'];
|
||||
expect(w['node/A']['node-param-conflict-A']).not.toBe(undefined);
|
||||
expect(WarningsModel.instance.getNumberOfWarningsForComponent(c)).toBe(1);
|
||||
});
|
||||
|
||||
it('can detect type conflict warnings', function () {
|
||||
var c = p.getComponentWithName('comp2');
|
||||
c.graph.evaluateHealth();
|
||||
|
||||
var w = WarningsModel.instance.warnings['comp2'];
|
||||
expect(w['node/B']['node-type-conflict']).not.toBe(undefined);
|
||||
expect(WarningsModel.instance.getNumberOfWarningsForComponent(c)).toBe(1);
|
||||
});
|
||||
|
||||
it('can clear warnings', function () {
|
||||
// Clear the warning
|
||||
var c = p.getComponentWithName('comp1');
|
||||
WarningsModel.instance.setWarning(
|
||||
{
|
||||
component: c,
|
||||
node: c.graph.roots[0],
|
||||
key: 'node-param-conflict-A'
|
||||
},
|
||||
undefined
|
||||
);
|
||||
expect(WarningsModel.instance.hasComponentWarnings(c)).toBe(false);
|
||||
|
||||
// Clear warnings
|
||||
var c = p.getComponentWithName('comp2');
|
||||
WarningsModel.instance.clearWarningsForRef({
|
||||
component: c,
|
||||
node: c.graph.roots[0]
|
||||
});
|
||||
expect(WarningsModel.instance.hasComponentWarnings(c)).toBe(false);
|
||||
});
|
||||
|
||||
it('can format warnings', function () {
|
||||
var c = p.getComponentWithName('comp3');
|
||||
c.graph.evaluateHealth();
|
||||
|
||||
var w = WarningsModel.instance.warnings['comp3'];
|
||||
expect(w['node/C']['node-param-conflict-alignX']).not.toBe(undefined);
|
||||
expect(w['node/C']['node-param-conflict-alignX'].warning.message).toEqual('Merge conflict at parameter AlignX');
|
||||
expect(w['node/C']['node-param-conflict-x']).not.toBe(undefined);
|
||||
expect(w['node/C']['node-param-conflict-x'].warning.message).toEqual('Merge conflict at parameter x');
|
||||
});
|
||||
|
||||
it('clear warnings when project is unloaded', function () {
|
||||
var c = p.getComponentWithName('comp1');
|
||||
c.graph.evaluateHealth();
|
||||
expect(WarningsModel.instance.hasComponentWarnings(c)).toBe(true);
|
||||
|
||||
ProjectModel.instance = undefined;
|
||||
expect(WarningsModel.instance.warnings).toEqual({});
|
||||
});
|
||||
|
||||
function getProject() {
|
||||
return {
|
||||
name: 'p',
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'group',
|
||||
id: 'A',
|
||||
conflicts: [
|
||||
{
|
||||
type: 'parameter',
|
||||
name: 'A',
|
||||
ours: 0,
|
||||
theirs: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'group',
|
||||
id: 'B',
|
||||
conflicts: [
|
||||
{
|
||||
type: 'typename',
|
||||
ours: '/a',
|
||||
theirs: '/b'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'comp3',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'group',
|
||||
id: 'C',
|
||||
conflicts: [
|
||||
{
|
||||
type: 'parameter',
|
||||
name: 'x',
|
||||
ours: {
|
||||
value: 10,
|
||||
unit: '%'
|
||||
},
|
||||
theirs: 10
|
||||
},
|
||||
{
|
||||
type: 'parameter',
|
||||
name: 'alignX',
|
||||
ours: 'left',
|
||||
theirs: 'right'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
51
packages/noodl-editor/tests/nodegraph/createnewnode.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const CreateNewNodePanel = require('@noodl-views/createnewnodepanel');
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
|
||||
describe('Create new node panel unit tests', function () {
|
||||
var p, cp;
|
||||
|
||||
xit('can setup panel', function () {
|
||||
ProjectModel.instance = new ProjectModel();
|
||||
|
||||
p = ProjectModel.fromJSON(project);
|
||||
|
||||
cp = new CreateNewNodePanel({
|
||||
model: p.getComponentWithName('Root').graph,
|
||||
pos: {
|
||||
x: 100,
|
||||
y: 50
|
||||
},
|
||||
runtimeType: 'browser'
|
||||
});
|
||||
cp.render();
|
||||
expect(cp).not.toBe(undefined);
|
||||
});
|
||||
|
||||
xit('can create nodes', function () {
|
||||
var c = p.getComponentWithName('Root');
|
||||
cp.performCreate(NodeLibrary.instance.getNodeTypeWithName('group'));
|
||||
|
||||
expect(c.graph.roots.length).toBe(2);
|
||||
expect(c.graph.roots[1].type).toBe(NodeLibrary.instance.getNodeTypeWithName('group'));
|
||||
expect(c.graph.roots[1].x).toBe(100);
|
||||
expect(c.graph.roots[1].y).toBe(50);
|
||||
expect(c.graph.roots[1].version).toBe(2);
|
||||
});
|
||||
|
||||
var project = {
|
||||
components: [
|
||||
{
|
||||
name: 'Root',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'A',
|
||||
type: 'group'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
101
packages/noodl-editor/tests/nodegraph/createstatus.js
Normal file
@@ -0,0 +1,101 @@
|
||||
const NodeGraphModel = require('@noodl-models/nodegraphmodel').NodeGraphModel;
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
const { ComponentModel } = require('@noodl-models/componentmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
|
||||
describe('Create status tests', function () {
|
||||
var g1, c1, c2;
|
||||
|
||||
beforeEach(() => {
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
});
|
||||
|
||||
it("can detect nodes that can't have/be children", function () {
|
||||
g1 = new NodeGraphModel();
|
||||
|
||||
c1 = new ComponentModel({
|
||||
graph: g1,
|
||||
name: 'c1'
|
||||
});
|
||||
|
||||
var n1 = NodeGraphNode.fromJSON(
|
||||
{
|
||||
type: 'group',
|
||||
id: 'A'
|
||||
},
|
||||
g1
|
||||
);
|
||||
g1.addRoot(n1);
|
||||
|
||||
var n2 = NodeGraphNode.fromJSON(
|
||||
{
|
||||
type: 'animation',
|
||||
id: 'B'
|
||||
},
|
||||
g1
|
||||
);
|
||||
g1.addRoot(n2);
|
||||
|
||||
var n3 = NodeGraphNode.fromJSON(
|
||||
{
|
||||
type: 'Component Children',
|
||||
id: 'C'
|
||||
},
|
||||
g1
|
||||
);
|
||||
g1.addRoot(n3);
|
||||
|
||||
// Nodes that can have children
|
||||
var status = c1.getCreateStatus({
|
||||
parent: n1,
|
||||
type: NodeLibrary.instance.getNodeTypeWithName('group')
|
||||
});
|
||||
expect(status.creatable).toBe(true);
|
||||
|
||||
// Animation nodes cannot be children
|
||||
var status = c1.getCreateStatus({
|
||||
parent: n1,
|
||||
type: NodeLibrary.instance.getNodeTypeWithName('animation')
|
||||
});
|
||||
expect(status.creatable).toBe(false);
|
||||
|
||||
// Animation nodes cannot have children
|
||||
var status = c1.getCreateStatus({
|
||||
parent: n2,
|
||||
type: NodeLibrary.instance.getNodeTypeWithName('group')
|
||||
});
|
||||
expect(status.creatable).toBe(false);
|
||||
|
||||
// Instance of itself
|
||||
var status = c1.getCreateStatus({
|
||||
type: c1
|
||||
});
|
||||
expect(status.creatable).toBe(false);
|
||||
});
|
||||
|
||||
it('can detect circular references', function () {
|
||||
c1 = ComponentModel.fromJSON({
|
||||
name: 'comp1',
|
||||
graph: {}
|
||||
});
|
||||
c2 = ComponentModel.fromJSON({
|
||||
name: 'comp2',
|
||||
graph: {}
|
||||
});
|
||||
c1.graph.addRoot(
|
||||
NodeGraphNode.fromJSON(
|
||||
{
|
||||
type: c2,
|
||||
id: 'C'
|
||||
},
|
||||
c1.graph
|
||||
)
|
||||
);
|
||||
|
||||
var status = c2.getCreateStatus({
|
||||
type: c1
|
||||
});
|
||||
expect(status.creatable).toBe(false);
|
||||
});
|
||||
});
|
||||
496
packages/noodl-editor/tests/nodegraph/export.js
Normal file
@@ -0,0 +1,496 @@
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const Exporter = require('@noodl-utils/exporter');
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('export tests', function () {
|
||||
xit('can export ports on components', function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON(project1);
|
||||
NodeLibrary.instance.registerModule(ProjectModel.instance);
|
||||
|
||||
ProjectModel.instance.setRootNode(ProjectModel.instance.findNodeWithId('Image-1'));
|
||||
|
||||
const json = Exporter.exportToJSON(ProjectModel.instance);
|
||||
|
||||
// Should not export types where the type has not been resolved
|
||||
expect(json.components[0].ports.length).toBe(2);
|
||||
expect(json.components[0].ports[0].name).toBe('out1');
|
||||
expect(json.components[0].ports[0].plug).toBe('output');
|
||||
expect(NodeLibrary.nameForPortType(json.components[0].ports[0].type)).toBe('string');
|
||||
expect(json.components[0].ports[1].name).toBe('out2');
|
||||
expect(json.components[0].ports[1].plug).toBe('output');
|
||||
expect(NodeLibrary.nameForPortType(json.components[0].ports[1].type)).toBe('number');
|
||||
|
||||
NodeLibrary.instance.unregisterModule(ProjectModel.instance);
|
||||
});
|
||||
|
||||
it('project settings are exported', function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON(project2);
|
||||
NodeLibrary.instance.registerModule(ProjectModel.instance);
|
||||
|
||||
ProjectModel.instance.setRootNode(ProjectModel.instance.findNodeWithId('Group-1'));
|
||||
|
||||
const json = Exporter.exportToJSON(ProjectModel.instance);
|
||||
expect(json.settings.canvasWidth).toBe(303);
|
||||
expect(json.settings.canvasHeight).toBe(404);
|
||||
|
||||
NodeLibrary.instance.unregisterModule(ProjectModel.instance);
|
||||
});
|
||||
|
||||
function matchBundle(bundle, componentIndex) {
|
||||
function arrayHasSameElements(a, b) {
|
||||
//check if equal but ignore order
|
||||
if (a.length !== b.length) return false;
|
||||
return a.every((e) => b.includes(e));
|
||||
}
|
||||
|
||||
return Object.values(componentIndex).some((b) => arrayHasSameElements(bundle, b));
|
||||
}
|
||||
|
||||
it('can export an index that includes pages and for each nodes', function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON({
|
||||
components: [
|
||||
{
|
||||
name: '/root',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'nav-stack',
|
||||
type: 'Page Stack',
|
||||
parameters: {
|
||||
pages: [
|
||||
{
|
||||
id: 'p1',
|
||||
label: 'Page1'
|
||||
},
|
||||
{
|
||||
id: 'p2',
|
||||
label: 'Page2'
|
||||
}
|
||||
],
|
||||
'pageComp-p1': '/page1',
|
||||
'pageComp-p2': '/page2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'n0',
|
||||
type: '/shared-comp'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/page1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'n0',
|
||||
type: '/shared-comp'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/page2',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/shared-comp',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/remaining-comp',
|
||||
graph: {}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ProjectModel.instance.setRootNode(ProjectModel.instance.findNodeWithId('nav-stack'));
|
||||
|
||||
const json = Exporter.exportToJSON(ProjectModel.instance);
|
||||
|
||||
//make sure the root components are present directly in the export, not in a bundle
|
||||
expect(json.components.find((c) => c.name === '/root'));
|
||||
expect(json.components.find((c) => c.name === '/shared-comp'));
|
||||
|
||||
//this test assume the bundles are emitted in a specific order
|
||||
//it makes the test tied to implementation specifics, so not great
|
||||
const bundles = {
|
||||
b2: {
|
||||
components: ['/page1'],
|
||||
dependencies: []
|
||||
},
|
||||
b3: {
|
||||
components: ['/page2'],
|
||||
dependencies: []
|
||||
},
|
||||
b4: {
|
||||
components: ['/remaining-comp'],
|
||||
dependencies: []
|
||||
}
|
||||
};
|
||||
|
||||
expect(json.componentIndex).toEqual(bundles);
|
||||
});
|
||||
|
||||
it('can follow For Each nodes when collecting dependencies', function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON({
|
||||
components: [
|
||||
{
|
||||
name: '/root',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'node1',
|
||||
type: 'For Each',
|
||||
parameters: {
|
||||
template: '/for-each-comp'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/for-each-comp',
|
||||
graph: {}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const allComponents = ProjectModel.instance.getComponents();
|
||||
const rootComponent = allComponents.find((c) => c.name === '/root');
|
||||
|
||||
const graph = Exporter._collectDependencyGraph(rootComponent, allComponents);
|
||||
const deps = Exporter._flattenDependencyGraph(graph);
|
||||
|
||||
expect(deps.length).toBe(2);
|
||||
expect(deps.find((c) => c.name === '/root'));
|
||||
expect(deps.find((c) => c.name === '/for-each-comp'));
|
||||
});
|
||||
|
||||
it("creates bundles that doesn't have duplicates", function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON({
|
||||
components: [
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'nav-stack',
|
||||
type: 'Page Stack',
|
||||
parameters: {
|
||||
pages: [
|
||||
{
|
||||
id: 'p1',
|
||||
label: 'Page1'
|
||||
},
|
||||
{
|
||||
id: 'p2',
|
||||
label: 'Page2'
|
||||
}
|
||||
],
|
||||
'pageComp-p1': '/page1',
|
||||
'pageComp-p2': '/page2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'n0',
|
||||
type: '/shared-comp'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/page1',
|
||||
id: 'page1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'n1',
|
||||
type: '/shared-comp'
|
||||
},
|
||||
{
|
||||
id: 'n2',
|
||||
type: '/comp-used-on-both-pages'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/page2',
|
||||
id: 'page2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'n3',
|
||||
type: '/comp-used-on-both-pages'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/shared-comp',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/comp-used-on-both-pages',
|
||||
graph: {}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ProjectModel.instance.setRootNode(ProjectModel.instance.findNodeWithId('nav-stack'));
|
||||
|
||||
const json = Exporter.exportToJSON(ProjectModel.instance);
|
||||
|
||||
const componentCount = {};
|
||||
for (const name in json.componentIndex) {
|
||||
for (const comp of json.componentIndex[name].components) {
|
||||
if (componentCount[comp]) componentCount[comp]++;
|
||||
else componentCount[comp] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (const name in componentCount) {
|
||||
expect(componentCount[name]).toBe(1, 'Component ' + name + ' is in multiple bundles');
|
||||
}
|
||||
});
|
||||
|
||||
it('calculated dependencies for bundles', function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON({
|
||||
components: [
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'nav-stack',
|
||||
type: 'Page Stack',
|
||||
parameters: {
|
||||
pages: [
|
||||
{
|
||||
id: 'p1',
|
||||
label: 'Page1'
|
||||
},
|
||||
{
|
||||
id: 'p2',
|
||||
label: 'Page2'
|
||||
}
|
||||
],
|
||||
'pageComp-p1': '/page1',
|
||||
'pageComp-p2': '/page2'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'n0',
|
||||
type: '/shared-comp'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/page1',
|
||||
id: 'page1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'n1',
|
||||
type: '/shared-comp'
|
||||
},
|
||||
{
|
||||
id: 'n2',
|
||||
type: '/comp-used-on-both-pages'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/page2',
|
||||
id: 'page2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'n3',
|
||||
type: '/comp-used-on-both-pages'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/shared-comp',
|
||||
graph: {}
|
||||
},
|
||||
{
|
||||
name: '/comp-used-on-both-pages',
|
||||
graph: {}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
ProjectModel.instance.setRootNode(ProjectModel.instance.findNodeWithId('nav-stack'));
|
||||
|
||||
const allComponents = ProjectModel.instance.getComponents();
|
||||
const rootComponent = allComponents.find((c) => c.name === '/comp1');
|
||||
|
||||
const componentIndex = Exporter.getComponentIndex(rootComponent, allComponents);
|
||||
|
||||
//this test assume the bundles are emitted in a specific order
|
||||
//it makes the test tied to implementation specifics, so not great
|
||||
const bundles = {
|
||||
b0: {
|
||||
components: ['/comp1'],
|
||||
dependencies: ['b1']
|
||||
},
|
||||
b1: {
|
||||
components: ['/shared-comp'],
|
||||
dependencies: []
|
||||
},
|
||||
b2: {
|
||||
components: ['/page1'],
|
||||
dependencies: ['b1', 'b3']
|
||||
},
|
||||
b3: {
|
||||
components: ['/comp-used-on-both-pages'],
|
||||
dependencies: []
|
||||
},
|
||||
b4: {
|
||||
components: ['/page2'],
|
||||
dependencies: ['b3']
|
||||
}
|
||||
};
|
||||
|
||||
expect(componentIndex).toEqual(bundles);
|
||||
});
|
||||
|
||||
xit('ignores project settings flagged to be excluded', function () {
|
||||
ProjectModel.instance = ProjectModel.fromJSON({
|
||||
components: [
|
||||
{
|
||||
name: '/comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'Group-1',
|
||||
type: 'group'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
settings: {
|
||||
someSetting: 'test',
|
||||
someSetting2: 'test2',
|
||||
settingIgnoredInExport: 'test3'
|
||||
}
|
||||
});
|
||||
|
||||
NodeLibrary.instance.registerModule(ProjectModel.instance);
|
||||
|
||||
ProjectModel.instance.setRootNode(ProjectModel.instance.findNodeWithId('Group-1'));
|
||||
|
||||
const json = Exporter.exportToJSON(ProjectModel.instance);
|
||||
expect(json.settings.someSetting).toBe('test');
|
||||
expect(json.settings.someSetting2).toBe('test2');
|
||||
expect(json.settings.settingIgnoredInExport).toBe(undefined);
|
||||
NodeLibrary.instance.unregisterModule(ProjectModel.instance);
|
||||
});
|
||||
|
||||
var project1 = {
|
||||
components: [
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'Image-1',
|
||||
type: 'image',
|
||||
parameters: {
|
||||
image: 'pic1.png',
|
||||
css: '%%%mycss {background:#ff00ff;}'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'Comp-2',
|
||||
type: '/comp2'
|
||||
},
|
||||
{
|
||||
id: 'CO-1',
|
||||
type: 'Component Outputs',
|
||||
ports: [
|
||||
{
|
||||
name: 'out1',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'out2',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
connections: [
|
||||
{
|
||||
fromId: 'Image-1',
|
||||
fromProperty: 'image',
|
||||
toId: 'CO-1',
|
||||
toProperty: 'out1'
|
||||
},
|
||||
{
|
||||
fromId: 'Image-1',
|
||||
fromProperty: 'screenX',
|
||||
toId: 'CO-1',
|
||||
toProperty: 'out2'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Should be excluded
|
||||
{
|
||||
name: '/comp3',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'Image-3',
|
||||
type: 'image'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: '/comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'Image-2',
|
||||
type: 'image'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Second project for cross project reference
|
||||
var project2 = {
|
||||
components: [
|
||||
{
|
||||
name: '/comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'Group-1',
|
||||
type: 'group'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
settings: {
|
||||
canvasWidth: 303,
|
||||
canvasHeight: 404
|
||||
}
|
||||
};
|
||||
});
|
||||
117
packages/noodl-editor/tests/nodegraph/hierarchy.js
Normal file
@@ -0,0 +1,117 @@
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
const { ComponentModel } = require('@noodl-models/componentmodel');
|
||||
|
||||
describe('Component instances', function () {
|
||||
var c;
|
||||
|
||||
beforeEach(() => {
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
|
||||
c = ComponentModel.fromJSON({
|
||||
name: 'test',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: 'group',
|
||||
id: 'Group-1'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('can load component', function () {
|
||||
expect(c).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('can detect children that can be attached', function () {
|
||||
const n1 = NodeGraphNode.fromJSON({
|
||||
type: 'image'
|
||||
});
|
||||
|
||||
const n2 = NodeGraphNode.fromJSON({
|
||||
type: 'animation'
|
||||
});
|
||||
|
||||
const n3 = NodeGraphNode.fromJSON({
|
||||
type: 'scaleModifier'
|
||||
});
|
||||
|
||||
const n4 = NodeGraphNode.fromJSON({
|
||||
type: 'image'
|
||||
});
|
||||
|
||||
// Can accept an image
|
||||
expect(c.graph.findNodeWithId('Group-1').canAcceptChildren([n1])).toBe(true);
|
||||
|
||||
// Not all nodes can be children
|
||||
expect(c.graph.findNodeWithId('Group-1').canAcceptChildren([n1, n2])).toBe(false);
|
||||
|
||||
// Not all nodes have accepted categories
|
||||
expect(c.graph.findNodeWithId('Group-1').canAcceptChildren([n1, n3])).toBe(false);
|
||||
|
||||
// Multiple nodes with same category should be OK
|
||||
expect(c.graph.findNodeWithId('Group-1').canAcceptChildren([n1, n4])).toBe(true);
|
||||
});
|
||||
|
||||
it('can report allow as child for components', function () {
|
||||
var c2 = ComponentModel.fromJSON({
|
||||
name: 'test',
|
||||
graph: {}
|
||||
});
|
||||
|
||||
// No root nodes that can be children
|
||||
expect(c2.allowAsChild).toBe(false);
|
||||
|
||||
c2.graph.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
type: 'group'
|
||||
})
|
||||
);
|
||||
|
||||
// Group can be child
|
||||
expect(c2.allowAsChild).toBe(true);
|
||||
|
||||
// Report correct category
|
||||
expect(c2.category).toBe('visuals');
|
||||
});
|
||||
|
||||
it('can report accepted children for components', function () {
|
||||
expect(c.allowChildrenWithCategory).toBe(undefined);
|
||||
|
||||
c.graph.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
type: 'Component Children'
|
||||
})
|
||||
);
|
||||
|
||||
expect(c.allowChildrenWithCategory).toEqual(['visuals']);
|
||||
|
||||
c.graph.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
type: 'Component Modifier Children'
|
||||
})
|
||||
);
|
||||
|
||||
expect(c.allowChildrenWithCategory).toEqual(['modifiers', 'visuals']);
|
||||
});
|
||||
|
||||
it('can detect allow export root', function () {
|
||||
var c2 = ComponentModel.fromJSON({
|
||||
name: 'test',
|
||||
graph: {}
|
||||
});
|
||||
|
||||
expect(c2.allowAsExportRoot).toBe(false);
|
||||
|
||||
c2.graph.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
type: 'group'
|
||||
})
|
||||
);
|
||||
|
||||
expect(c2.allowAsExportRoot).toBe(true);
|
||||
});
|
||||
});
|
||||
11
packages/noodl-editor/tests/nodegraph/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export * from './conflictwarnings';
|
||||
export * from './createnewnode';
|
||||
export * from './createstatus';
|
||||
export * from './export';
|
||||
export * from './hierarchy';
|
||||
export * from './nodegrapheditor';
|
||||
export * from './nodegraphmodel';
|
||||
export * from './nodelibrary-spec';
|
||||
export * from './propertyeditor';
|
||||
export * from './typechangepropagation';
|
||||
export * from './warnings-model-spec';
|
||||
574
packages/noodl-editor/tests/nodegraph/nodegrapheditor.js
Normal file
@@ -0,0 +1,574 @@
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
const NodeGraphEditor = require('@noodl-views/nodegrapheditor').NodeGraphEditor;
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const PopupLayer = require('@noodl-views/popuplayer');
|
||||
const DebugInspector = require('@noodl-utils/debuginspector');
|
||||
const ViewerConnection = require('../../src/editor/src/ViewerConnection');
|
||||
|
||||
describe('Node graph editor auto tests', function () {
|
||||
var c1, g1;
|
||||
|
||||
// Records and store mouse calls to the node graph editor
|
||||
var storeTimeout;
|
||||
var recordedEvents = [];
|
||||
|
||||
function storeEvents() {
|
||||
clearTimeout(storeTimeout);
|
||||
storeTimeout = setTimeout(function () {
|
||||
localStorage['recordedEvents'] = JSON.stringify(recordedEvents);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function recordEvents() {
|
||||
var types = ['mousedown', 'mousemove', 'mouseup'];
|
||||
|
||||
// mouse
|
||||
var old = NodeGraphEditor.instance.mouse;
|
||||
NodeGraphEditor.instance.mouse = function (type, pos, evt) {
|
||||
var now = +new Date();
|
||||
recordedEvents.push({
|
||||
type: type,
|
||||
time: now,
|
||||
x: pos.x,
|
||||
y: pos.y,
|
||||
evt: evt
|
||||
? {
|
||||
button: evt.button,
|
||||
shiftKey: evt.shiftKey ? true : undefined,
|
||||
ctrlKey: evt.ctrlKey ? true : undefined,
|
||||
spaceKey: evt.spaceKey ? true : undefined
|
||||
}
|
||||
: undefined
|
||||
});
|
||||
|
||||
storeEvents();
|
||||
|
||||
return old.call(this, type, pos, evt);
|
||||
};
|
||||
|
||||
// cut, copy, paste
|
||||
var oldCut = NodeGraphEditor.instance.cut;
|
||||
NodeGraphEditor.instance.cut = function () {
|
||||
var now = +new Date();
|
||||
recordedEvents.push({
|
||||
type: 'cut',
|
||||
time: now
|
||||
});
|
||||
return oldCut.call(this);
|
||||
};
|
||||
|
||||
var oldCopy = NodeGraphEditor.instance.copy;
|
||||
NodeGraphEditor.instance.copy = function () {
|
||||
var now = +new Date();
|
||||
recordedEvents.push({
|
||||
type: 'copy',
|
||||
time: now
|
||||
});
|
||||
return oldCopy.call(this);
|
||||
};
|
||||
|
||||
var oldPaste = NodeGraphEditor.instance.paste;
|
||||
NodeGraphEditor.instance.paste = function () {
|
||||
var now = +new Date();
|
||||
recordedEvents.push({
|
||||
type: 'paste',
|
||||
time: now
|
||||
});
|
||||
return oldPaste.call(this);
|
||||
};
|
||||
}
|
||||
|
||||
// Plays back previously stored mouse calls
|
||||
function playEvents(events, done, realtime) {
|
||||
var i = 0;
|
||||
|
||||
function play() {
|
||||
var event = events[i];
|
||||
var type = event.type;
|
||||
if (type === 'cut') {
|
||||
NodeGraphEditor.instance.cut();
|
||||
} else if (type === 'copy') {
|
||||
NodeGraphEditor.instance.copy();
|
||||
} else if (type === 'paste') {
|
||||
NodeGraphEditor.instance.paste();
|
||||
} else {
|
||||
NodeGraphEditor.instance.mouse(
|
||||
event.type,
|
||||
{
|
||||
x: event.x,
|
||||
y: event.y
|
||||
},
|
||||
event.evt
|
||||
);
|
||||
}
|
||||
|
||||
if (events[i + 1]) {
|
||||
setTimeout(function () {
|
||||
i++;
|
||||
play();
|
||||
}, events[i + 1].time - event.time);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
play();
|
||||
}
|
||||
|
||||
// Sets up a fresh node graph editor
|
||||
function setup() {
|
||||
$('body').append(
|
||||
'<div id="node-graph-editor" style="position:absolute; top:0px; right:0px; width:400px; height:800px; background-color:white;"></div>'
|
||||
);
|
||||
|
||||
// Disable context menu
|
||||
$('body').on('contextmenu', function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
// NodeLibrary.instance = new NodeLibrary();
|
||||
|
||||
ProjectModel.instance = ProjectModel.fromJSON(project);
|
||||
NodeLibrary.instance.registerModule(ProjectModel.instance);
|
||||
|
||||
c1 = ProjectModel.instance.getComponentWithName('Root');
|
||||
g1 = c1.graph;
|
||||
|
||||
// Mocking panel instance
|
||||
PopupLayer.instance = {
|
||||
showTooltip: function () {},
|
||||
hideTooltip: function () {},
|
||||
showToast: function () {},
|
||||
on: function () {},
|
||||
hidePopup: function () {},
|
||||
showPopup: function () {},
|
||||
isDragging: function () {
|
||||
return false;
|
||||
},
|
||||
showModal: function () {},
|
||||
hideModal: function () {},
|
||||
hideAllModalsAndPopups: function () {}
|
||||
};
|
||||
|
||||
// Mocking viewer connection
|
||||
ViewerConnection.instance = {
|
||||
on: function () {},
|
||||
sendNodeHighlighted: function () {}
|
||||
};
|
||||
|
||||
NodeGraphEditor.instance = new NodeGraphEditor({
|
||||
model: g1
|
||||
});
|
||||
NodeGraphEditor.instance.setPanAndScale({
|
||||
scale: 1,
|
||||
x: 0,
|
||||
y: 0
|
||||
});
|
||||
NodeGraphEditor.instance.render();
|
||||
$('#node-graph-editor').append(NodeGraphEditor.instance.el);
|
||||
NodeGraphEditor.instance.resize({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 400,
|
||||
height: 800
|
||||
});
|
||||
}
|
||||
|
||||
var project = {
|
||||
components: [
|
||||
{
|
||||
name: 'Root',
|
||||
ports: [],
|
||||
visual: true,
|
||||
visualRootId: '14e31556-f569-21bb-e948-65af515ae574',
|
||||
canHaveVisualChildren: false,
|
||||
graph: {
|
||||
connections: [],
|
||||
roots: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
function setupNodes() {
|
||||
g1.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
id: '14e31556-f569-21bb-e948-65af515ae574',
|
||||
type: 'group',
|
||||
label: 'group1',
|
||||
x: 49,
|
||||
y: 75
|
||||
})
|
||||
);
|
||||
|
||||
g1.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
id: '33a2be5c-b341-27b4-292f-aee1b5bc30fe',
|
||||
type: 'group',
|
||||
label: 'group2',
|
||||
x: 49,
|
||||
y: 164
|
||||
})
|
||||
);
|
||||
|
||||
g1.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
id: '34ea0053-3334-d2cb-3a31-de577030102e',
|
||||
type: 'group',
|
||||
label: 'group3',
|
||||
x: 49,
|
||||
y: 267
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function setupNodes2() {
|
||||
g1.addRoot(
|
||||
NodeGraphNode.fromJSON({
|
||||
id: 'A',
|
||||
type: 'group',
|
||||
label: 'group4',
|
||||
x: 49,
|
||||
y: 367
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function setupConnections() {
|
||||
g1.addConnection({
|
||||
fromId: '14e31556-f569-21bb-e948-65af515ae574',
|
||||
fromProperty: 'screenX',
|
||||
toId: '33a2be5c-b341-27b4-292f-aee1b5bc30fe',
|
||||
toProperty: 'x'
|
||||
});
|
||||
}
|
||||
|
||||
function setupConnections2() {
|
||||
g1.addConnection({
|
||||
fromId: '34ea0053-3334-d2cb-3a31-de577030102e',
|
||||
fromProperty: 'screenX',
|
||||
toId: '33a2be5c-b341-27b4-292f-aee1b5bc30fe',
|
||||
toProperty: 'x'
|
||||
});
|
||||
|
||||
g1.addConnection({
|
||||
fromId: '14e31556-f569-21bb-e948-65af515ae574',
|
||||
fromProperty: 'screenX',
|
||||
toId: '34ea0053-3334-d2cb-3a31-de577030102e',
|
||||
toProperty: 'y'
|
||||
});
|
||||
}
|
||||
|
||||
function teardownNodes() {
|
||||
g1.removeAllNodes();
|
||||
}
|
||||
|
||||
// Closes and tears the node graph editor down
|
||||
function teardown() {
|
||||
$('#node-graph-editor').remove();
|
||||
NodeGraphEditor.instance = undefined;
|
||||
}
|
||||
|
||||
it('can setup view', function () {
|
||||
setup();
|
||||
expect(NodeGraphEditor.instance).not.toBe(undefined);
|
||||
});
|
||||
|
||||
/* it('can record events',function(done) {
|
||||
setupNodes();
|
||||
// setupNodes2();
|
||||
recordEvents();
|
||||
});
|
||||
return;*/
|
||||
|
||||
// Multi re arrange
|
||||
xit('Multi rearrange nodes, attach, detach', function (done) {
|
||||
setupNodes();
|
||||
setupNodes2();
|
||||
|
||||
playEvents(require('../recordings/multirearrange.json'), function () {
|
||||
expect(g1.roots.length).toBe(2);
|
||||
|
||||
var n1 = g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574');
|
||||
var n2 = g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe');
|
||||
var n3 = g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e');
|
||||
var n4 = g1.findNodeWithId('A');
|
||||
|
||||
expect(n1.children[0]).toBe(n3);
|
||||
expect(n4.children[0]).toBe(n2);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
xit('cut n paste', function (done) {
|
||||
setupNodes();
|
||||
|
||||
playEvents(require('../recordings/cutnpaste.json'), function () {
|
||||
expect(g1.roots.length).toBe(3);
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe')).not.toBe(undefined);
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e')).not.toBe(undefined);
|
||||
expect(g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574')).not.toBe(undefined);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
xit('can undo attach, detach and move', function (done) {
|
||||
setupNodes();
|
||||
|
||||
playEvents(require('../recordings/undoarrange.json'), function () {
|
||||
// group3
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e').parent).toBe(undefined);
|
||||
|
||||
// group2 child to group1
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe').parent).toBe(
|
||||
g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574')
|
||||
);
|
||||
|
||||
NodeGraphEditor.instance.undo(); // Undo detach
|
||||
|
||||
// group3 child to group1
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e').parent).toBe(
|
||||
g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574')
|
||||
);
|
||||
|
||||
NodeGraphEditor.instance.undo(); // Undo attach
|
||||
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e').parent).toBe(undefined);
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe').parent).toBe(undefined);
|
||||
|
||||
NodeGraphEditor.instance.undo(); // Undo move
|
||||
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e').x).toBe(49);
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e').y).toBe(267);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Single re arrange
|
||||
xit('single rearrange nodes, attach, detach', function (done) {
|
||||
setupNodes();
|
||||
|
||||
playEvents(require('../recordings/singlerearrange.json'), function () {
|
||||
var n = g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574');
|
||||
expect(n.parent).toBe(undefined);
|
||||
|
||||
var n1 = g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe');
|
||||
var n2 = g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e');
|
||||
|
||||
expect(n1.parent).toBe(n);
|
||||
expect(n2.parent).toBe(n);
|
||||
|
||||
expect(n.children[0]).toBe(n2);
|
||||
expect(n.children[1]).toBe(n1);
|
||||
|
||||
expect(g1.roots.length).toBe(1);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Multi select and mode nodes
|
||||
xit('can multiselect and move nodes', function (done) {
|
||||
setupNodes();
|
||||
|
||||
playEvents(require('../recordings/multimove.json'), function () {
|
||||
var n1 = NodeGraphEditor.instance.model.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574');
|
||||
var n2 = NodeGraphEditor.instance.model.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe');
|
||||
|
||||
expect(n1.x).toBe(50);
|
||||
expect(n1.y).toBe(365);
|
||||
|
||||
expect(n2.x).toBe(50);
|
||||
expect(n2.y).toBe(454);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Drag to move nodes
|
||||
xit('can move nodes', function (done) {
|
||||
setupNodes();
|
||||
|
||||
playEvents(require('../recordings/movenode.json'), function () {
|
||||
var n = NodeGraphEditor.instance.model.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574');
|
||||
expect(n.x).toBe(47);
|
||||
expect(n.y).toBe(408);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
xit('can undo cut and paste', function (done) {
|
||||
setupNodes();
|
||||
|
||||
playEvents(require('../recordings/undocutpaste.json'), function () {
|
||||
expect(g1.roots.length).toBe(3);
|
||||
expect(g1.roots[1].label).toBe('group2');
|
||||
expect(g1.roots[2].label).toBe('group3');
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe')).toBe(undefined);
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e')).toBe(undefined);
|
||||
|
||||
NodeGraphEditor.instance.undo(); // Undo paste
|
||||
|
||||
expect(g1.roots.length).toBe(1);
|
||||
|
||||
NodeGraphEditor.instance.undo(); // Undo cut
|
||||
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe')).not.toBe(undefined);
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e')).not.toBe(undefined);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Undo cut children
|
||||
xit('Can undo cut children', function (done) {
|
||||
setupNodes();
|
||||
setupNodes2();
|
||||
|
||||
playEvents(require('../recordings/undocutchildren.json'), function () {
|
||||
expect(g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574').children[0]).toBe(g1.findNodeWithId('A'));
|
||||
|
||||
NodeGraphEditor.instance.undo();
|
||||
|
||||
expect(g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574').children[0]).toBe(
|
||||
g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe')
|
||||
);
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe').children[0]).toBe(
|
||||
g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e')
|
||||
);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Undo cut connections
|
||||
xit('Can undo cut connections', function (done) {
|
||||
setupNodes();
|
||||
setupConnections();
|
||||
setupConnections2();
|
||||
|
||||
playEvents(require('../recordings/undocutconnections.json'), function () {
|
||||
expect(g1.connections.length).toBe(0);
|
||||
|
||||
NodeGraphEditor.instance.undo();
|
||||
|
||||
expect(g1.connections.length).toBe(3);
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Can delete and undo connection
|
||||
xit('can delete and undo delete connection', function (done) {
|
||||
setupNodes();
|
||||
setupConnections();
|
||||
|
||||
playEvents(require('../recordings/deletecon.json'), function () {
|
||||
expect(g1.connections.length).toBe(0);
|
||||
NodeGraphEditor.instance.undo();
|
||||
expect(g1.connections.length).toBe(1);
|
||||
expect(g1.connections[0].fromId).toBe('14e31556-f569-21bb-e948-65af515ae574');
|
||||
|
||||
expect(NodeGraphEditor.instance.verifyWithModel()).toBe(true);
|
||||
teardownNodes();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Delete
|
||||
xit('can delete nodes and undo', function (done) {
|
||||
setupNodes();
|
||||
setupConnections();
|
||||
|
||||
playEvents(require('../recordings/deleteandundo.json'), function () {
|
||||
NodeGraphEditor.instance.delete();
|
||||
|
||||
expect(g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574')).toBe(undefined);
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe')).toBe(undefined);
|
||||
expect(g1.findNodeWithId('34ea0053-3334-d2cb-3a31-de577030102e')).not.toBe(undefined);
|
||||
expect(g1.connections.length).toBe(0);
|
||||
|
||||
NodeGraphEditor.instance.undo();
|
||||
|
||||
expect(g1.findNodeWithId('14e31556-f569-21bb-e948-65af515ae574')).not.toBe(undefined);
|
||||
expect(g1.findNodeWithId('33a2be5c-b341-27b4-292f-aee1b5bc30fe')).not.toBe(undefined);
|
||||
expect(g1.connections.length).toBe(1);
|
||||
teardownNodes();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
xit('Can create inspectors', function (done) {
|
||||
setupNodes();
|
||||
setupConnections();
|
||||
setupConnections2();
|
||||
|
||||
playEvents(
|
||||
require('../recordings/connectiondebugger.json'),
|
||||
function () {
|
||||
var model = DebugInspector.InspectorsModel.instanceForProject(ProjectModel.instance);
|
||||
var inspectors = model.getInspectors();
|
||||
expect(inspectors[1]).toEqual({
|
||||
connectionKey: '14e31556-f569-21bb-e948-65af515ae574screenX33a2be5c-b341-27b4-292f-aee1b5bc30fex',
|
||||
pinned: true,
|
||||
position: 0.390625,
|
||||
type: 'connection',
|
||||
connection: {
|
||||
fromId: '14e31556-f569-21bb-e948-65af515ae574',
|
||||
fromProperty: 'screenX',
|
||||
toId: '33a2be5c-b341-27b4-292f-aee1b5bc30fe',
|
||||
toProperty: 'x'
|
||||
}
|
||||
});
|
||||
expect(inspectors[0]).toEqual({
|
||||
connectionKey: '34ea0053-3334-d2cb-3a31-de577030102escreenX33a2be5c-b341-27b4-292f-aee1b5bc30fex',
|
||||
pinned: true,
|
||||
position: 0.515625,
|
||||
type: 'connection',
|
||||
connection: {
|
||||
fromId: '34ea0053-3334-d2cb-3a31-de577030102e',
|
||||
fromProperty: 'screenX',
|
||||
toId: '33a2be5c-b341-27b4-292f-aee1b5bc30fe',
|
||||
toProperty: 'x'
|
||||
}
|
||||
});
|
||||
expect(inspectors.length).toBe(2);
|
||||
|
||||
teardownNodes();
|
||||
done();
|
||||
},
|
||||
true
|
||||
); // Play in real time
|
||||
});
|
||||
|
||||
// Multi select and mode nodes
|
||||
it('can tear down', function () {
|
||||
teardown();
|
||||
expect(NodeGraphEditor.instance).toBe(undefined);
|
||||
});
|
||||
});
|
||||
173
packages/noodl-editor/tests/nodegraph/nodegraphmodel.js
Normal file
@@ -0,0 +1,173 @@
|
||||
const NodeGraphModel = require('@noodl-models/nodegraphmodel').NodeGraphModel;
|
||||
const NodeGraphNode = require('@noodl-models/nodegraphmodel').NodeGraphNode;
|
||||
|
||||
describe('Node graph basic tests', function () {
|
||||
it('fires nodeAdded, nodeRemoved and connectionAdded, connectionRemoved events', function () {
|
||||
const g1 = new NodeGraphModel();
|
||||
|
||||
var handlers = jasmine.createSpyObj('handlers', [
|
||||
'nodeAdded',
|
||||
'nodeRemoved',
|
||||
'connectionAdded',
|
||||
'connectionRemoved'
|
||||
]);
|
||||
|
||||
g1.on('nodeAdded', handlers.nodeAdded);
|
||||
g1.on('nodeRemoved', handlers.nodeRemoved);
|
||||
g1.on('connectionAdded', handlers.connectionAdded);
|
||||
g1.on('connectionRemoved', handlers.connectionRemoved);
|
||||
|
||||
const n1 = NodeGraphNode.fromJSON({
|
||||
type: 'layer',
|
||||
id: 'A'
|
||||
});
|
||||
g1.addRoot(n1);
|
||||
|
||||
expect(handlers.nodeAdded.calls.argsFor(0)[0].model).toBe(n1);
|
||||
|
||||
const n2 = NodeGraphNode.fromJSON({
|
||||
type: 'layer',
|
||||
id: 'B'
|
||||
});
|
||||
g1.addRoot(n2);
|
||||
|
||||
expect(handlers.nodeAdded.calls.argsFor(1)[0].model).toBe(n2);
|
||||
|
||||
const con = {
|
||||
fromId: 'A',
|
||||
fromProperty: 'color',
|
||||
toId: 'B',
|
||||
toProperty: 'color'
|
||||
};
|
||||
g1.addConnection(con);
|
||||
expect(handlers.connectionAdded.calls.argsFor(0)[0].model).toBe(con);
|
||||
|
||||
g1.removeConnection(con);
|
||||
expect(handlers.connectionRemoved.calls.argsFor(0)[0].model).toBe(con);
|
||||
|
||||
g1.removeNode(n2);
|
||||
expect(handlers.nodeRemoved.calls.argsFor(0)[0].model).toBe(n2);
|
||||
});
|
||||
|
||||
it('can change the id on all nodes', () => {
|
||||
const g1 = new NodeGraphModel();
|
||||
const n1 = NodeGraphNode.fromJSON({
|
||||
type: 'layer',
|
||||
id: 'A'
|
||||
});
|
||||
g1.addRoot(n1);
|
||||
const n2 = NodeGraphNode.fromJSON({
|
||||
type: 'layer',
|
||||
id: 'B'
|
||||
});
|
||||
g1.addRoot(n2);
|
||||
|
||||
const con = {
|
||||
fromId: 'A',
|
||||
fromProperty: 'color',
|
||||
toId: 'B',
|
||||
toProperty: 'color'
|
||||
};
|
||||
g1.addConnection(con);
|
||||
|
||||
g1.rekeyAllIds();
|
||||
|
||||
expect(n1.id).not.toEqual('A');
|
||||
expect(n2.id).not.toEqual('B');
|
||||
expect(con.fromId).toEqual(n1.id);
|
||||
expect(con.toId).toEqual(n2.id);
|
||||
});
|
||||
|
||||
describe('tracks what nodes are in the graph correctly', () => {
|
||||
it('can add and remove one node', () => {
|
||||
const graph = new NodeGraphModel();
|
||||
|
||||
//add a root
|
||||
expect(graph.findNodeWithId('A')).toBeFalsy();
|
||||
const n1 = NodeGraphNode.fromJSON({
|
||||
type: 'test',
|
||||
id: 'A'
|
||||
});
|
||||
graph.addRoot(n1);
|
||||
expect(graph.findNodeWithId('A')).toBeTruthy();
|
||||
|
||||
//and then remove it
|
||||
graph.removeNode(n1);
|
||||
expect(graph.findNodeWithId('A')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('can add and remove a node with children', () => {
|
||||
const graph = new NodeGraphModel();
|
||||
|
||||
//add a new root with children and verify that both nodes are found
|
||||
const n2 = NodeGraphNode.fromJSON({
|
||||
type: 'test',
|
||||
id: 'A',
|
||||
children: [
|
||||
{
|
||||
type: 'test',
|
||||
id: 'B'
|
||||
}
|
||||
]
|
||||
});
|
||||
graph.addRoot(n2);
|
||||
|
||||
expect(graph.findNodeWithId('A')).toBe(n2);
|
||||
expect(graph.findNodeWithId('B')).toBe(n2.children[0]);
|
||||
|
||||
//remove the root and verify that both nodes are removed
|
||||
graph.removeNode(n2);
|
||||
expect(graph.findNodeWithId('A')).toBeFalsy();
|
||||
expect(graph.findNodeWithId('B')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('can add a child node to a root', () => {
|
||||
const graph = new NodeGraphModel();
|
||||
|
||||
const root = NodeGraphNode.fromJSON({
|
||||
type: 'test',
|
||||
id: 'A'
|
||||
});
|
||||
graph.addRoot(root);
|
||||
|
||||
const child = NodeGraphNode.fromJSON({
|
||||
type: 'test',
|
||||
id: 'B'
|
||||
});
|
||||
|
||||
root.addChild(child);
|
||||
|
||||
expect(graph.findNodeWithId('A')).toBe(root);
|
||||
expect(graph.findNodeWithId('B')).toBe(child);
|
||||
|
||||
const child2 = NodeGraphNode.fromJSON({
|
||||
type: 'test',
|
||||
id: 'C'
|
||||
});
|
||||
|
||||
root.insertChild(child2, 0);
|
||||
|
||||
expect(graph.findNodeWithId('C')).toBe(child2);
|
||||
});
|
||||
|
||||
it('can remove a child node to a root', () => {
|
||||
const graph = new NodeGraphModel();
|
||||
|
||||
const n2 = NodeGraphNode.fromJSON({
|
||||
type: 'test',
|
||||
id: 'A',
|
||||
children: [
|
||||
{
|
||||
type: 'test',
|
||||
id: 'B'
|
||||
}
|
||||
]
|
||||
});
|
||||
graph.addRoot(n2);
|
||||
graph.removeNode(n2.children[0]);
|
||||
|
||||
expect(graph.findNodeWithId('B')).toBeFalsy();
|
||||
expect(graph.findNodeWithId('A')).toBe(n2);
|
||||
});
|
||||
});
|
||||
});
|
||||
318
packages/noodl-editor/tests/nodegraph/nodelibrary-spec.js
Normal file
@@ -0,0 +1,318 @@
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const BasicNodeType = require('@noodl-models/nodelibrary/BasicNodeType').BasicNodeType;
|
||||
const UnknownNodeType = require('@noodl-models/nodelibrary/UnknownNodeType').UnknownNodeType;
|
||||
|
||||
const { ComponentModel } = require('@noodl-models/componentmodel');
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
|
||||
describe('Node library tests', function () {
|
||||
beforeEach(() => {
|
||||
//reload fresh library for every test
|
||||
window.NodeLibraryData = require('../nodegraph/nodelibrary');
|
||||
for (const module of NodeLibrary.instance.modules) {
|
||||
NodeLibrary.instance.unregisterModule(module);
|
||||
}
|
||||
|
||||
NodeLibrary.instance.loadLibrary();
|
||||
});
|
||||
|
||||
it('can detect compatibale port types', function () {
|
||||
// Equal types
|
||||
expect(NodeLibrary.instance.canCastPortTypes('string', 'string')).toBe(true);
|
||||
expect(
|
||||
NodeLibrary.instance.canCastPortTypes(
|
||||
{
|
||||
name: 'string'
|
||||
},
|
||||
'string'
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
NodeLibrary.instance.canCastPortTypes('string', {
|
||||
name: 'string'
|
||||
})
|
||||
).toBe(true);
|
||||
|
||||
// Not equal and cannot cast
|
||||
expect(
|
||||
NodeLibrary.instance.canCastPortTypes('string', {
|
||||
name: 'signal'
|
||||
})
|
||||
).toBe(false);
|
||||
|
||||
// Star types are compatible with everything
|
||||
expect(
|
||||
NodeLibrary.instance.canCastPortTypes('*', {
|
||||
name: 'number'
|
||||
})
|
||||
).toBe(true);
|
||||
|
||||
// Casting
|
||||
expect(
|
||||
NodeLibrary.instance.canCastPortTypes('number', {
|
||||
name: 'string'
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('can find compatible port types', function () {
|
||||
// Single type
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'string'
|
||||
}
|
||||
])
|
||||
).toEqual({
|
||||
name: 'string'
|
||||
});
|
||||
|
||||
// Multiple connections, same type, with modifiers
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
direction: 'from',
|
||||
type: {
|
||||
name: 'string',
|
||||
multiline: true
|
||||
}
|
||||
}
|
||||
])
|
||||
).toEqual({
|
||||
name: 'string',
|
||||
multiline: true
|
||||
});
|
||||
|
||||
// Is enums merged
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: {
|
||||
name: 'enum',
|
||||
enums: ['a', 'b']
|
||||
}
|
||||
},
|
||||
{
|
||||
direction: 'from',
|
||||
type: {
|
||||
name: 'enum',
|
||||
enums: ['b', 'c']
|
||||
}
|
||||
}
|
||||
])
|
||||
).toEqual({
|
||||
name: 'enum',
|
||||
enums: ['a', 'b', 'c']
|
||||
});
|
||||
|
||||
// Find compatible type and merge
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: {
|
||||
name: 'number',
|
||||
allowConnectionsOnly: true
|
||||
}
|
||||
},
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'boolean'
|
||||
}
|
||||
])
|
||||
).toEqual({
|
||||
name: 'number',
|
||||
allowConnectionsOnly: true
|
||||
});
|
||||
|
||||
// Find compatible type, mixed direction
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: {
|
||||
name: 'number',
|
||||
allowEditOnly: true
|
||||
}
|
||||
},
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
direction: 'from',
|
||||
type: 'number'
|
||||
}
|
||||
])
|
||||
).toEqual({
|
||||
name: 'number',
|
||||
allowEditOnly: true
|
||||
});
|
||||
|
||||
// Find compatible type, mixed direction
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: {
|
||||
name: 'number'
|
||||
}
|
||||
},
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
direction: 'from',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'color'
|
||||
}
|
||||
])
|
||||
).toEqual({
|
||||
name: 'string'
|
||||
});
|
||||
|
||||
// Can't find compatible type
|
||||
expect(
|
||||
NodeLibrary.instance.findCompatiblePortType([
|
||||
{
|
||||
direction: 'to',
|
||||
type: {
|
||||
name: 'number',
|
||||
allowEditOnly: true
|
||||
}
|
||||
},
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
direction: 'from',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
direction: 'to',
|
||||
type: 'referece'
|
||||
}
|
||||
])
|
||||
).toBe(undefined);
|
||||
});
|
||||
|
||||
it('can reload library', function () {
|
||||
var p = ProjectModel.fromJSON(getProject());
|
||||
NodeLibrary.instance.registerModule(p);
|
||||
|
||||
var n1 = p.components[0].graph.findNodeWithId('A');
|
||||
var n2 = p.components[0].graph.findNodeWithId('B');
|
||||
var n3 = p.components[0].graph.findNodeWithId('C');
|
||||
var n4 = p.components[0].graph.findNodeWithId('D');
|
||||
|
||||
expect(n1.type instanceof BasicNodeType).toBe(true);
|
||||
expect(n1.type.name).toBe('image');
|
||||
expect(n2.type instanceof UnknownNodeType).toBe(true);
|
||||
|
||||
// Update library
|
||||
NodeLibraryData.nodetypes.push({
|
||||
name: 'newimage',
|
||||
allowAsChild: true,
|
||||
allowAsExclusiveRootOnly: true,
|
||||
category: 'visuals',
|
||||
ports: [
|
||||
{
|
||||
name: 'x',
|
||||
type: {
|
||||
name: 'number'
|
||||
},
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
});
|
||||
NodeLibrary.instance.reload();
|
||||
|
||||
// Both should be OK now
|
||||
expect(n1.type instanceof BasicNodeType).toBe(true);
|
||||
expect(n1.type.name).toBe('image');
|
||||
|
||||
expect(n2.type instanceof BasicNodeType).toBe(true);
|
||||
expect(n2.type.name).toBe('newimage');
|
||||
|
||||
NodeLibrary.instance.unregisterModule(p);
|
||||
});
|
||||
|
||||
it('can get types by name', () => {
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('comp1')).toBeUndefined();
|
||||
//get basic type from node library
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('image')).toBeInstanceOf(BasicNodeType);
|
||||
|
||||
//get component type from a project
|
||||
const p = ProjectModel.fromJSON(getProject());
|
||||
NodeLibrary.instance.registerModule(p);
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('comp1')).toBeInstanceOf(ComponentModel);
|
||||
|
||||
//add a new component and get the type
|
||||
const newComponent = ComponentModel.fromJSON({
|
||||
name: 'comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'B',
|
||||
type: 'image'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
p.addComponent(newComponent);
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('comp2')).toBe(newComponent);
|
||||
|
||||
//remove the component again
|
||||
p.removeComponent(newComponent);
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('comp2')).toBeUndefined();
|
||||
|
||||
//unregister project and make sure the components aren't available anymore
|
||||
NodeLibrary.instance.unregisterModule(p);
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('comp1')).toBeUndefined();
|
||||
expect(NodeLibrary.instance.getNodeTypeWithName('comp2')).toBeUndefined();
|
||||
});
|
||||
|
||||
function getProject() {
|
||||
return {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'A',
|
||||
type: 'image'
|
||||
},
|
||||
{
|
||||
id: 'B',
|
||||
type: 'newimage'
|
||||
},
|
||||
{
|
||||
id: 'C',
|
||||
type: 'Event Sender',
|
||||
parameters: {
|
||||
channel: 'Channel0'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'D',
|
||||
type: 'Event Receiver'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
751
packages/noodl-editor/tests/nodegraph/nodelibrary.js
Normal file
@@ -0,0 +1,751 @@
|
||||
function createTestNodeLibrary() {
|
||||
return {
|
||||
projectsettings: {
|
||||
dynamicports: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'settingIgnoredInExport',
|
||||
type: 'string',
|
||||
ignoreInExport: true
|
||||
},
|
||||
{
|
||||
name: 'someSetting',
|
||||
type: 'string',
|
||||
ignoreInExport: false
|
||||
},
|
||||
{
|
||||
name: 'someSetting2',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
},
|
||||
typecasts: [
|
||||
{
|
||||
from: 'boolean',
|
||||
to: []
|
||||
},
|
||||
{
|
||||
from: 'number',
|
||||
to: ['string', 'boolean']
|
||||
},
|
||||
{
|
||||
from: 'string',
|
||||
to: ['number', 'boolean', 'color']
|
||||
}
|
||||
],
|
||||
dynamicports: [
|
||||
{
|
||||
type: 'conditionalports',
|
||||
name: 'basic'
|
||||
},
|
||||
{
|
||||
type: 'expand',
|
||||
name: 'basic'
|
||||
},
|
||||
{
|
||||
type: 'portchannel',
|
||||
name: 'event-sender-channel',
|
||||
channelPortname: 'channel',
|
||||
typename: 'Event Sender',
|
||||
ignorePorts: ['channel']
|
||||
},
|
||||
{
|
||||
type: 'numbered',
|
||||
name: 'basic-number',
|
||||
port: {
|
||||
type: 'number'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'regexp',
|
||||
name: 'expression-js',
|
||||
filters: [
|
||||
{
|
||||
type: 'replace',
|
||||
comment: 'Removed javascript style comments',
|
||||
regexp: '((\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/))',
|
||||
args: 'mg',
|
||||
with: ''
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp: '"[^"]+"',
|
||||
args: 'g',
|
||||
with: ''
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp: "'[^']+'",
|
||||
args: 'g',
|
||||
with: ''
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp:
|
||||
'(break|case|class|catch|const|continue|debugger|default|delete|do|else|export|extends|finally|for|function|if|import|in|instanceof|let|new|return|super|switch|this|throw|try|typeof|var|void|while|with|yield)',
|
||||
args: 'g',
|
||||
with: ''
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp: '\\s',
|
||||
args: 'g',
|
||||
with: ''
|
||||
},
|
||||
{
|
||||
type: 'ignore',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*(?=\\()'
|
||||
},
|
||||
{
|
||||
type: 'ignore',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*(?=\\=)'
|
||||
},
|
||||
{
|
||||
type: 'ports',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*(?=\\:boolean)',
|
||||
args: 'g',
|
||||
port: {
|
||||
type: {
|
||||
name: 'boolean'
|
||||
},
|
||||
plug: 'input'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*\\:boolean',
|
||||
args: 'g'
|
||||
},
|
||||
{
|
||||
type: 'ports',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*(?=\\:string)',
|
||||
args: 'g',
|
||||
port: {
|
||||
type: {
|
||||
name: 'string'
|
||||
},
|
||||
plug: 'input'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*\\:string',
|
||||
args: 'g'
|
||||
},
|
||||
{
|
||||
type: 'ports',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*(?=\\:number)',
|
||||
args: 'g',
|
||||
port: {
|
||||
type: {
|
||||
name: 'number'
|
||||
},
|
||||
plug: 'input'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'replace',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*\\:number',
|
||||
args: 'g'
|
||||
},
|
||||
{
|
||||
type: 'ports',
|
||||
regexp: '([a-z]|[A-Z])([a-z]|\\.|[A-Z]|[0-9])*',
|
||||
args: 'g',
|
||||
port: {
|
||||
type: {
|
||||
name: '=',
|
||||
default: 'string',
|
||||
allowedTypes: ['string', 'boolean', 'number']
|
||||
},
|
||||
plug: 'input'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
nodetypes: [
|
||||
{
|
||||
name: 'Component Outputs',
|
||||
haveComponentPorts: true,
|
||||
color: 'component',
|
||||
ports: []
|
||||
},
|
||||
{
|
||||
name: 'Component Inputs',
|
||||
color: 'component',
|
||||
haveComponentPorts: true,
|
||||
ports: []
|
||||
},
|
||||
{
|
||||
name: 'Component Children',
|
||||
color: 'component',
|
||||
category: 'visuals',
|
||||
allowSingleInstanceOnly: true,
|
||||
haveComponentChildren: ['visuals']
|
||||
},
|
||||
{
|
||||
name: 'Component Modifier Children',
|
||||
color: 'component',
|
||||
category: 'modifiers',
|
||||
allowSingleInstanceOnly: true,
|
||||
haveComponentChildren: ['modifiers']
|
||||
},
|
||||
{
|
||||
name: 'group',
|
||||
version: 2,
|
||||
allowAsChild: true,
|
||||
allowAsExportRoot: true,
|
||||
category: 'visuals',
|
||||
allowChildrenWithCategory: ['visuals'],
|
||||
ports: [
|
||||
{
|
||||
name: 'compref',
|
||||
type: 'component',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
group: 'test',
|
||||
name: 'x',
|
||||
type: {
|
||||
name: 'number',
|
||||
units: ['px', '%']
|
||||
},
|
||||
default: {
|
||||
value: 10,
|
||||
unit: '%'
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
group: 'test',
|
||||
name: 'y',
|
||||
type: {
|
||||
name: 'number'
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'opacity',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
displayName: 'AlignX',
|
||||
name: 'alignX',
|
||||
type: {
|
||||
name: 'enum',
|
||||
enums: [
|
||||
{
|
||||
value: 'left',
|
||||
label: 'Left'
|
||||
},
|
||||
{
|
||||
value: 'center',
|
||||
label: 'Center'
|
||||
},
|
||||
{
|
||||
value: 'right',
|
||||
label: 'Right'
|
||||
}
|
||||
]
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'alignY',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['top', 'center', 'bottom']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'scaleX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'scaleY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'width',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'fill',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['parent', 'width', 'height', 'aspectFill', 'aspectFit']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'pivotX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'pivotY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'layoutX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'layoutY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'depth',
|
||||
type: {
|
||||
name: 'number',
|
||||
casts: ['boolean']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'rotationX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'rotationY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'rotationZ',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'touchPropagation',
|
||||
type: {
|
||||
name: 'boolean',
|
||||
casts: ['number']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'layout',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['stackVertical', 'stackHorizontal', 'flowVertical', 'flowHorizontal', 'none']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'clip',
|
||||
type: 'boolean',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
group: 'test',
|
||||
name: 'screenX',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
group: 'test',
|
||||
name: 'screenY',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'width',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'this',
|
||||
type: 'reference',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'clipOut',
|
||||
type: 'boolean',
|
||||
plug: 'output'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
allowAsChild: true,
|
||||
allowAsExclusiveRootOnly: true,
|
||||
category: 'visuals',
|
||||
ports: [
|
||||
{
|
||||
name: 'x',
|
||||
type: {
|
||||
name: 'number'
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'y',
|
||||
type: {
|
||||
name: 'number'
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'opacity',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'alignX',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['left', 'center', 'right']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'alignY',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['top', 'center', 'bottom']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'scaleX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'scaleY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'width',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'fill',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['parent', 'width', 'height', 'aspectFill', 'aspectFit']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'pivotX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'pivotY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'layoutX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'layoutY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'depth',
|
||||
type: {
|
||||
name: 'number',
|
||||
casts: ['boolean']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'rotationX',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'rotationY',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'rotationZ',
|
||||
type: 'number',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'touchPropagation',
|
||||
type: {
|
||||
name: 'boolean',
|
||||
casts: ['number']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'blendMode',
|
||||
type: {
|
||||
name: 'string',
|
||||
enums: ['normal', 'solid', 'additive', 'multiply']
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
type: 'color',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
type: {
|
||||
name: 'string'
|
||||
},
|
||||
allowEditOnly: true,
|
||||
plug: 'input/output'
|
||||
},
|
||||
{
|
||||
name: 'image2',
|
||||
type: {
|
||||
name: 'image'
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'font',
|
||||
type: {
|
||||
name: 'font'
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'css',
|
||||
type: {
|
||||
name: 'string',
|
||||
codeeditor: 'css'
|
||||
},
|
||||
allowEditOnly: true,
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'shader',
|
||||
type: 'shader',
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
group: 'gruppen',
|
||||
name: 'screenX',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'screenY',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'width',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'height',
|
||||
type: 'number',
|
||||
plug: 'output'
|
||||
},
|
||||
{
|
||||
name: 'this',
|
||||
type: 'reference',
|
||||
plug: 'output'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'animation'
|
||||
},
|
||||
{
|
||||
name: 'scaleModifier',
|
||||
category: 'modifiers'
|
||||
},
|
||||
{
|
||||
name: 'nodeWithNumberedPorts',
|
||||
dynamicports: [
|
||||
{
|
||||
name: 'numbered/basic-number',
|
||||
prefix: 'my number',
|
||||
displayPrefix: 'My number',
|
||||
port: {
|
||||
group: 'My group'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'nodeWithNumberedPortsAndSelectors',
|
||||
dynamicports: [
|
||||
{
|
||||
name: 'numbered/basic-number',
|
||||
prefix: 'my number',
|
||||
displayPrefix: 'My number',
|
||||
port: {
|
||||
group: 'My group'
|
||||
},
|
||||
selectors: [
|
||||
{
|
||||
name: 'startAt',
|
||||
displayName: 'Start at',
|
||||
group: 'My selectors'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'javascript expression',
|
||||
usePortAsLabel: 'expression',
|
||||
dynamicports: [
|
||||
{
|
||||
name: 'regexp/expression-js',
|
||||
port: 'expression'
|
||||
}
|
||||
],
|
||||
ports: [
|
||||
{
|
||||
name: 'expression',
|
||||
type: {
|
||||
name: 'string',
|
||||
multiline: true
|
||||
},
|
||||
plug: 'input'
|
||||
},
|
||||
{
|
||||
name: 'result',
|
||||
type: '=',
|
||||
plug: 'output'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Event Sender',
|
||||
ports: [
|
||||
{
|
||||
name: 'channel',
|
||||
type: 'string',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Event Receiver',
|
||||
dynamicports: [
|
||||
{
|
||||
name: 'portchannel/event-sender-channel',
|
||||
channelPort: {
|
||||
name: 'channel',
|
||||
displayName: 'Channel',
|
||||
plug: 'input'
|
||||
},
|
||||
port: {
|
||||
type: '*',
|
||||
plug: 'output'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Anim',
|
||||
dynamicports: [
|
||||
{
|
||||
name: 'conditionalports/basic',
|
||||
condition: 'type = typeA',
|
||||
ports: [
|
||||
{
|
||||
name: 'from',
|
||||
plug: 'input',
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'conditionalports/basic',
|
||||
condition: 'type != typeA',
|
||||
ports: [
|
||||
{
|
||||
name: 'to',
|
||||
plug: 'input',
|
||||
type: 'number'
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
ports: [
|
||||
{
|
||||
name: 'type',
|
||||
type: 'string',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'ExpandPorts',
|
||||
dynamicports: [
|
||||
{
|
||||
name: 'expand/basic',
|
||||
indexStep: 100,
|
||||
template: [
|
||||
{
|
||||
name: '{{portname}}.A',
|
||||
plug: 'input',
|
||||
type: 'number',
|
||||
index: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'expand/basic',
|
||||
indexStep: 100,
|
||||
condition: "'{{portname}}.A' = test OR '{{portname}}.A' NOT SET",
|
||||
template: [
|
||||
{
|
||||
name: '{{portname}}.B',
|
||||
plug: 'input',
|
||||
type: 'number',
|
||||
index: 2
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = createTestNodeLibrary();
|
||||
92
packages/noodl-editor/tests/nodegraph/propertyeditor.js
Normal file
@@ -0,0 +1,92 @@
|
||||
const { PropertyEditor } = require('@noodl-views/panels/propertyeditor/propertyeditor');
|
||||
const { NodeGraphNodeRename } = require('@noodl-views/panels/propertyeditor');
|
||||
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const { UndoQueue } = require('@noodl-models/undo-queue-model');
|
||||
|
||||
describe('Property editor panel unit tests', function () {
|
||||
var pe, n, c;
|
||||
|
||||
beforeEach(() => {
|
||||
ProjectModel.instance = ProjectModel.fromJSON(project);
|
||||
NodeLibrary.instance.registerModule(ProjectModel.instance);
|
||||
|
||||
c = ProjectModel.instance.getComponentWithName('Root');
|
||||
n = c.graph.findNodeWithId('A');
|
||||
pe = new PropertyEditor({
|
||||
model: n
|
||||
});
|
||||
pe.render();
|
||||
});
|
||||
|
||||
afterEach((done) => {
|
||||
//some tests schedule renders with a setTimeout
|
||||
//so schedule one ourselves before we clean up so the console
|
||||
//isn't filled with errors
|
||||
setTimeout(() => {
|
||||
ProjectModel.instance = undefined;
|
||||
done();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
it('can delete node and undo', function () {
|
||||
pe.performDelete();
|
||||
|
||||
expect(c.graph.findNodeWithId('A')).toBe(undefined);
|
||||
expect(c.graph.connections.length).toBe(0);
|
||||
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(c.graph.findNodeWithId('A')).not.toBe(undefined);
|
||||
expect(c.graph.connections.length).toBe(1);
|
||||
});
|
||||
|
||||
it('can rename and undo', function () {
|
||||
NodeGraphNodeRename(n, 'test');
|
||||
|
||||
expect(c.graph.findNodeWithId('A').label).toBe('test');
|
||||
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(c.graph.findNodeWithId('A').label).toBe('group');
|
||||
});
|
||||
|
||||
it('can edit parameter and undo', function () {
|
||||
pe.portsView.setParameter('alpha', 0.5);
|
||||
|
||||
expect(c.graph.findNodeWithId('A').parameters['alpha']).toBe(0.5);
|
||||
|
||||
UndoQueue.instance.undo();
|
||||
|
||||
expect(c.graph.findNodeWithId('A').parameters['alpha']).toBe(undefined);
|
||||
});
|
||||
|
||||
var project = {
|
||||
components: [
|
||||
{
|
||||
name: 'Root',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'A',
|
||||
type: 'group'
|
||||
},
|
||||
{
|
||||
id: 'B',
|
||||
type: 'group'
|
||||
}
|
||||
],
|
||||
connections: [
|
||||
{
|
||||
fromId: 'A',
|
||||
toId: 'B',
|
||||
fromProperty: 'x',
|
||||
toProperty: 'y'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
234
packages/noodl-editor/tests/nodegraph/typechangepropagation.js
Normal file
@@ -0,0 +1,234 @@
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const { ComponentModel } = require('@noodl-models/componentmodel');
|
||||
|
||||
describe('Type change propagation', function () {
|
||||
var p;
|
||||
|
||||
it('can load project', function () {
|
||||
p = ProjectModel.fromJSON(project1);
|
||||
NodeLibrary.instance.registerModule(p);
|
||||
expect(p).not.toBe(undefined);
|
||||
});
|
||||
|
||||
xit('can remove connections and type will propagate', function () {
|
||||
// Remove connections
|
||||
var comp2 = p.getComponentWithName('/comp2');
|
||||
comp2.graph.removeConnection(comp2.graph.connections[0]);
|
||||
comp2.graph.removeConnection(comp2.graph.connections[0]);
|
||||
|
||||
// Component types should now have propagated and been set to undefined
|
||||
var comp1 = p.getComponentWithName('/comp1');
|
||||
expect(NodeLibrary.nameForPortType(comp1.findPortWithName('in1').type)).toBe(undefined);
|
||||
expect(NodeLibrary.nameForPortType(comp1.findPortWithName('out2').type)).toBe(undefined);
|
||||
});
|
||||
|
||||
xit('can reconnect and type will propagate', function () {
|
||||
// Add connections
|
||||
var comp2 = p.getComponentWithName('/comp2');
|
||||
var comp1 = p.getComponentWithName('/comp1');
|
||||
|
||||
comp2.graph.addConnection({
|
||||
fromId: 'a05abb49-625e-8bd6-7183-7ea07a46e1d4',
|
||||
fromProperty: 'screenX',
|
||||
toId: '6783bee9-1225-5840-354f-348a3d270b6d',
|
||||
toProperty: 'out2'
|
||||
});
|
||||
comp2.graph.addConnection({
|
||||
fromId: 'b1a816da-5023-18a2-59ba-9c58be5cd073',
|
||||
fromProperty: 'in1',
|
||||
toId: 'a05abb49-625e-8bd6-7183-7ea07a46e1d4',
|
||||
toProperty: 'image'
|
||||
});
|
||||
|
||||
// The types should have propagetd to comp1
|
||||
expect(NodeLibrary.nameForPortType(comp1.findPortWithName('in1').type)).toBe('string');
|
||||
expect(NodeLibrary.nameForPortType(comp1.findPortWithName('out2').type)).toBe('number');
|
||||
});
|
||||
|
||||
xit('removing a type results in undefined type', function () {
|
||||
var n1 = p.getComponentWithName('/comp').graph.findNodeWithId('A');
|
||||
p.getComponentWithName('/comp').graph.evaluateHealth();
|
||||
|
||||
expect(n1.getHealth().healthy).toBe(false);
|
||||
expect(n1.type.localName).toBe('notfound');
|
||||
expect(n1.type.fullName).toBe('/notfound');
|
||||
|
||||
p.addComponent(
|
||||
ComponentModel.fromJSON({
|
||||
name: '/notfound',
|
||||
graph: {}
|
||||
})
|
||||
);
|
||||
p.getComponentWithName('/comp').graph.evaluateHealth();
|
||||
|
||||
expect(n1.getHealth().healthy).toBe(true); // Node type should now be found
|
||||
});
|
||||
|
||||
xit('can remove type and create new one with new name', function () {
|
||||
var n1 = p.getComponentWithName('/comp').graph.findNodeWithId('A');
|
||||
|
||||
var comp = p.getComponentWithName('/notfound');
|
||||
p.removeComponent(comp);
|
||||
p.getComponentWithName('/comp').graph.evaluateHealth();
|
||||
|
||||
expect(n1.getHealth().healthy).toBe(false); // Health should be bad again
|
||||
var comp2 = ComponentModel.fromJSON({
|
||||
name: '/notfound',
|
||||
graph: {}
|
||||
});
|
||||
|
||||
p.addComponent(comp2);
|
||||
p.getComponentWithName('/comp').graph.evaluateHealth();
|
||||
expect(n1.getHealth().healthy).toBe(true); // The new type should be resolved
|
||||
expect(n1.type).toBe(comp2);
|
||||
expect(n1.toJSON().type).toBe('/notfound');
|
||||
});
|
||||
|
||||
xit('can rename components, type is changed', function () {
|
||||
var n1 = p.getComponentWithName('/comp').graph.findNodeWithId('A');
|
||||
|
||||
// rename the type
|
||||
p.renameComponentWithName('/notfound', '/notfound2');
|
||||
expect(n1.getHealth().healthy).toBe(true); // The new type should be resolved
|
||||
expect(n1.typename).toBe('/notfound2');
|
||||
});
|
||||
|
||||
var project1 = {
|
||||
components: [
|
||||
{
|
||||
name: '/comp',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'A',
|
||||
type: '/notfound'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/comp1',
|
||||
graph: {
|
||||
connections: [
|
||||
{
|
||||
fromId: '7f6b3382-b5c9-ae85-3614-3a3d0b31e4ce',
|
||||
fromProperty: 'out2',
|
||||
toId: 'd72cfb77-8515-8612-efed-c92e3f533b8b',
|
||||
toProperty: 'out2'
|
||||
},
|
||||
{
|
||||
fromId: '15a67805-e2ee-1fa4-b86a-4efc04e7028d',
|
||||
fromProperty: 'in1',
|
||||
toId: '7f6b3382-b5c9-ae85-3614-3a3d0b31e4ce',
|
||||
toProperty: 'in1'
|
||||
}
|
||||
],
|
||||
roots: [
|
||||
{
|
||||
id: 'd72cfb77-8515-8612-efed-c92e3f533b8b',
|
||||
type: 'Component Outputs',
|
||||
x: 274,
|
||||
y: 185,
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'out2',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '7f6b3382-b5c9-ae85-3614-3a3d0b31e4ce',
|
||||
type: '/comp2',
|
||||
x: 530,
|
||||
y: 185,
|
||||
parameters: {},
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: '15a67805-e2ee-1fa4-b86a-4efc04e7028d',
|
||||
type: 'Component Inputs',
|
||||
x: 792,
|
||||
y: 186,
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'in1',
|
||||
type: '*',
|
||||
plug: 'output'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/comp2',
|
||||
visual: true,
|
||||
visualRootId: 'a05abb49-625e-8bd6-7183-7ea07a46e1d4',
|
||||
canHaveVisualChildren: false,
|
||||
graph: {
|
||||
connections: [
|
||||
{
|
||||
fromId: 'a05abb49-625e-8bd6-7183-7ea07a46e1d4',
|
||||
fromProperty: 'this',
|
||||
toId: '6783bee9-1225-5840-354f-348a3d270b6d',
|
||||
toProperty: 'out2'
|
||||
},
|
||||
{
|
||||
fromId: 'b1a816da-5023-18a2-59ba-9c58be5cd073',
|
||||
fromProperty: 'in1',
|
||||
toId: 'a05abb49-625e-8bd6-7183-7ea07a46e1d4',
|
||||
toProperty: 'x'
|
||||
}
|
||||
],
|
||||
roots: [
|
||||
{
|
||||
id: '6783bee9-1225-5840-354f-348a3d270b6d',
|
||||
type: 'Component Outputs',
|
||||
x: 686,
|
||||
y: 150,
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'out2',
|
||||
type: '*',
|
||||
plug: 'input'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'a05abb49-625e-8bd6-7183-7ea07a46e1d4',
|
||||
type: 'image',
|
||||
x: 426,
|
||||
y: 147,
|
||||
parameters: {},
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 'b1a816da-5023-18a2-59ba-9c58be5cd073',
|
||||
type: 'Component Inputs',
|
||||
x: 169,
|
||||
y: 148,
|
||||
parameters: {},
|
||||
children: [],
|
||||
ports: [
|
||||
{
|
||||
name: 'in1',
|
||||
type: '*',
|
||||
plug: 'output'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
name: 'proj1'
|
||||
};
|
||||
});
|
||||
32
packages/noodl-editor/tests/nodegraph/warnings-model-spec.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const WarningsModel = require('@noodl-models/warningsmodel').WarningsModel;
|
||||
|
||||
describe('Warnings model', function () {
|
||||
beforeEach(() => {
|
||||
//since warningsmodel is global there can be warnings left over from other tests, make sure to clear them
|
||||
WarningsModel.instance.clearAllWarnings();
|
||||
});
|
||||
|
||||
it('can remove warnings using a callback for matching', function () {
|
||||
WarningsModel.instance.setWarning(
|
||||
{
|
||||
key: 'test-warning-remove'
|
||||
},
|
||||
{
|
||||
message: 'test warning'
|
||||
}
|
||||
);
|
||||
WarningsModel.instance.setWarning(
|
||||
{
|
||||
key: 'test-warning'
|
||||
},
|
||||
{
|
||||
message: 'test warning'
|
||||
}
|
||||
);
|
||||
|
||||
expect(WarningsModel.instance.getTotalNumberOfWarnings()).toBe(2);
|
||||
|
||||
WarningsModel.instance.clearWarningsForRefMatching((ref) => ref.key.includes('remove'));
|
||||
expect(WarningsModel.instance.getTotalNumberOfWarnings()).toBe(1);
|
||||
});
|
||||
});
|
||||
80
packages/noodl-editor/tests/platform/filesystem.js
Normal file
@@ -0,0 +1,80 @@
|
||||
var FileSystem = require('@noodl-utils/filesystem'),
|
||||
Utils = require('@noodl-utils/utils'),
|
||||
Process = require('process'),
|
||||
path = require('path');
|
||||
|
||||
const remote = require('@electron/remote');
|
||||
const App = remote.app;
|
||||
|
||||
// TODO: Skipped because the folder contained package.json, which was picked up by lerna.
|
||||
xdescribe('File system', function () {
|
||||
/* it("can handle component rename",function() {
|
||||
|
||||
var base = JSON.parse( fs.readFileSync(Process.cwd() + '/tests/testfs/merge-tests/base-merge-project-Tue--19-Jan-2021-11-26-44-GMT.json') );
|
||||
var ours = JSON.parse( fs.readFileSync(Process.cwd() + '/tests/testfs/merge-tests/ours-merge-project-Tue--19-Jan-2021-11-26-44-GMT.json') );
|
||||
var remote = JSON.parse( fs.readFileSync(Process.cwd() + '/tests/testfs/merge-tests/remote-merge-project-Tue--19-Jan-2021-11-26-44-GMT.json') );
|
||||
|
||||
var res = ProjectMerger.mergeProject(base, ours, remote);
|
||||
|
||||
expect(res.components[3].name).toBe("/UI Components/UI Elements/Rider Section - List Item");
|
||||
})
|
||||
return;*/
|
||||
|
||||
it('can sync dirs', function () {
|
||||
const tempDir = App.getPath('temp') + '/noodlunittests-filesystem-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
FileSystem.instance.copyRecursiveSync(Process.cwd() + '/tests/testfs/fs_sync_dir_tests/dst1', tempDir + '/dst1');
|
||||
|
||||
FileSystem.instance.syncDirsRecursiveSync(
|
||||
Process.cwd() + '/tests/testfs/fs_sync_dir_tests/src1',
|
||||
tempDir + '/dst1'
|
||||
);
|
||||
|
||||
expect(fs.existsSync(tempDir + '/dst1/popout-will-be-removed.svg')).toBe(false);
|
||||
expect(fs.existsSync(tempDir + '/dst1/should-be-removed/test.js')).toBe(false);
|
||||
expect(fs.existsSync(tempDir + '/dst1/project.json')).toBe(true);
|
||||
expect(fs.existsSync(tempDir + '/dst1/loginsplash.jpg')).toBe(true);
|
||||
expect(fs.existsSync(tempDir + '/dst1/test.js')).toBe(true);
|
||||
expect(fs.existsSync(tempDir + '/dst1/test/ajax-loader.gif')).toBe(true);
|
||||
expect(fs.existsSync(tempDir + '/dst1/one/delete-me/Roboto-Black.ttf')).toBe(false);
|
||||
expect(fs.existsSync(tempDir + '/dst1/one/two/loginsplash2.jpg')).toBe(true);
|
||||
});
|
||||
|
||||
it('can remove dirs without a slash ending', function (done) {
|
||||
const tempDir = App.getPath('temp') + '/noodlunittests-filesystem-' + Utils.guid();
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
|
||||
FileSystem.instance.copyRecursiveSync(Process.cwd() + '/tests/testfs/fs_sync_dir_tests/dst1', tempDir);
|
||||
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, () => {
|
||||
expect(fs.existsSync(tempDir)).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can remove dirs with a slash ending', function (done) {
|
||||
const tempDir = App.getPath('temp') + '/noodlunittests-filesystem-' + Utils.guid() + '/';
|
||||
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
FileSystem.instance.copyRecursiveSync(Process.cwd() + '/tests/testfs/fs_sync_dir_tests/dst1', tempDir);
|
||||
FileSystem.instance.removeDirectoryRecursive(tempDir, () => {
|
||||
expect(fs.existsSync(tempDir)).toBe(false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can copy dirs and ignore specific files', function () {
|
||||
const tempDir = App.getPath('temp') + '/noodlunittests-filesystem-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectorySync(tempDir);
|
||||
FileSystem.instance.copyRecursiveSync(Process.cwd() + '/tests/testfs/fs_sync_dir_tests/src1', tempDir, {
|
||||
filter(src) {
|
||||
return !src.includes(path.sep + 'test' + path.sep);
|
||||
}
|
||||
});
|
||||
|
||||
expect(fs.existsSync(tempDir + 'test/ajax-loader.gif')).toBe(false);
|
||||
expect(fs.existsSync(tempDir + 'loginsplash.jpg')).toBe(true);
|
||||
expect(fs.existsSync(tempDir + 'project.json')).toBe(true);
|
||||
expect(fs.existsSync(tempDir + 'test.js')).toBe(true);
|
||||
});
|
||||
});
|
||||
1
packages/noodl-editor/tests/platform/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './filesystem';
|
||||
4
packages/noodl-editor/tests/project/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// export * from './projectcloudsync'; //this is the old version control system
|
||||
export * from './projectimport';
|
||||
export * from './projectmodel';
|
||||
export * from './projectvalidator';
|
||||
358
packages/noodl-editor/tests/project/projectimport.js
Normal file
@@ -0,0 +1,358 @@
|
||||
const ProjectImporter = require('@noodl-utils/projectimporter');
|
||||
const FileSystem = require('@noodl-utils/filesystem');
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const Utils = require('@noodl-utils/utils');
|
||||
const Process = require('process');
|
||||
const ncp = require('ncp').ncp;
|
||||
const fs = require('fs');
|
||||
const { projectFromDirectory } = require('@noodl-models/projectmodel.editor');
|
||||
|
||||
const remote = require('@electron/remote');
|
||||
const App = remote.app;
|
||||
|
||||
describe('Project import and export unit tests', function () {
|
||||
function expectFilesToExist(direntry, paths, callback) {
|
||||
var filesToCheck = paths.length;
|
||||
var success = true;
|
||||
|
||||
function done() {
|
||||
filesToCheck--;
|
||||
if (filesToCheck === 0) callback(success);
|
||||
}
|
||||
|
||||
for (var i in paths) {
|
||||
FileSystem.instance.fileExists(direntry + '/' + paths[i], function (exists) {
|
||||
if (!exists) success = false;
|
||||
done();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
it('can import project with styles and variants', function (done) {
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj5',
|
||||
function (imports) {
|
||||
expect(imports.styles.colors).toEqual([
|
||||
{
|
||||
name: 'Primary'
|
||||
},
|
||||
{
|
||||
name: 'Light Gray'
|
||||
},
|
||||
{
|
||||
name: 'Dark Gray'
|
||||
},
|
||||
{
|
||||
name: 'Primary Dark'
|
||||
},
|
||||
{
|
||||
name: 'Dark'
|
||||
},
|
||||
{
|
||||
name: 'Primary Light'
|
||||
}
|
||||
]);
|
||||
|
||||
expect(imports.styles.text).toEqual([
|
||||
{
|
||||
name: 'Body Text',
|
||||
fileDependencies: ['fonts/Roboto/Roboto-Regular.ttf']
|
||||
},
|
||||
{
|
||||
name: 'Button Label',
|
||||
fileDependencies: ['fonts/Roboto/Roboto-Regular.ttf']
|
||||
},
|
||||
{
|
||||
name: 'Label Text',
|
||||
fileDependencies: ['fonts/Roboto/Roboto-Regular.ttf']
|
||||
}
|
||||
]);
|
||||
|
||||
expect(imports.variants).toEqual([
|
||||
{
|
||||
name: 'Basic',
|
||||
typename: 'net.noodl.controls.button',
|
||||
fileDependencies: ['fonts/Roboto/Roboto-Medium.ttf'],
|
||||
styleDependencies: {
|
||||
colors: ['Primary', 'Primary Light', 'Primary Dark', 'Light Gray'],
|
||||
text: ['Button Label']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Search Field',
|
||||
typename: 'net.noodl.controls.textinput',
|
||||
fileDependencies: ['fonts/Roboto/Roboto-Medium.ttf'],
|
||||
styleDependencies: {
|
||||
colors: ['Light Gray', 'Dark', 'Primary'],
|
||||
text: ['Body Text', 'Label Text']
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('can check for collissions (with styles and variants)', function (done) {
|
||||
projectFromDirectory(Process.cwd() + '/tests/testfs/import_proj5', function (project) {
|
||||
ProjectModel.instance = project;
|
||||
|
||||
// Now check for collistions with project to import
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj5',
|
||||
function (imports) {
|
||||
ProjectImporter.instance.checkForCollisions(imports, function (collisions) {
|
||||
expect(collisions.components.length).toBe(2);
|
||||
expect(collisions.modules.length).toBe(1);
|
||||
expect(collisions.resources.length).toBe(13);
|
||||
expect(collisions.variants.length).toBe(2);
|
||||
expect(collisions.styles.colors.length).toBe(6);
|
||||
expect(collisions.styles.text.length).toBe(3);
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('can list components and dependencies', function (done) {
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj1',
|
||||
function (imports) {
|
||||
console.log(imports);
|
||||
expect(imports.components).toEqual([
|
||||
{
|
||||
name: '/comp1',
|
||||
dependencies: [],
|
||||
fileDependencies: ['assets/bear.jpg'],
|
||||
styleDependencies: {
|
||||
text: [],
|
||||
colors: []
|
||||
},
|
||||
variantDependencies: []
|
||||
},
|
||||
{
|
||||
name: '/comp2',
|
||||
dependencies: [],
|
||||
fileDependencies: [],
|
||||
styleDependencies: {
|
||||
text: [],
|
||||
colors: []
|
||||
},
|
||||
variantDependencies: []
|
||||
},
|
||||
{
|
||||
name: '/Main',
|
||||
dependencies: ['/comp1'],
|
||||
fileDependencies: ['Fontfabric - Nexa-Bold.otf'],
|
||||
styleDependencies: {
|
||||
text: [],
|
||||
colors: []
|
||||
},
|
||||
variantDependencies: []
|
||||
}
|
||||
]);
|
||||
|
||||
expect(imports.styles).toEqual({
|
||||
text: [],
|
||||
colors: []
|
||||
});
|
||||
|
||||
//the order of these are different on mac and windows, so sort them
|
||||
imports.resources.sort((a, b) => {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
expect(imports.resources).toEqual([
|
||||
{
|
||||
name: 'assets/bear.jpg'
|
||||
},
|
||||
{
|
||||
name: 'assets/bikeyellowbuilding.jpg'
|
||||
},
|
||||
{
|
||||
name: 'bear.jpg'
|
||||
},
|
||||
{
|
||||
name: 'Fontfabric - Nexa-Bold.otf'
|
||||
}
|
||||
]);
|
||||
|
||||
expect(imports.variants).toEqual([]);
|
||||
expect(imports.modules).toEqual([]);
|
||||
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('can check for collissions (1)', function (done) {
|
||||
projectFromDirectory(Process.cwd() + '/tests/testfs/import_proj1', function (project) {
|
||||
ProjectModel.instance = project;
|
||||
|
||||
// Now check for collistions with project to import
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj2',
|
||||
function (imports) {
|
||||
ProjectImporter.instance.checkForCollisions(imports, function (collisions) {
|
||||
expect(collisions.components.length).toBe(1);
|
||||
expect(collisions.components[0].name).toBe('/Main');
|
||||
|
||||
expect(collisions.resources).toEqual([]);
|
||||
expect(collisions.modules).toEqual([]);
|
||||
expect(collisions.variants).toEqual([]);
|
||||
expect(collisions.styles).toEqual({
|
||||
colors: [],
|
||||
text: []
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('can check for collissions (2)', function (done) {
|
||||
projectFromDirectory(Process.cwd() + '/tests/testfs/import_proj1', function (project) {
|
||||
ProjectModel.instance = project;
|
||||
|
||||
// Now check for collistions with project to import
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj3',
|
||||
function (imports) {
|
||||
ProjectImporter.instance.checkForCollisions(imports, function (collisions) {
|
||||
expect(collisions.resources).toEqual([
|
||||
{
|
||||
name: 'Fontfabric - Nexa-Bold.otf'
|
||||
},
|
||||
{
|
||||
name: 'assets/bear.jpg'
|
||||
}
|
||||
]);
|
||||
|
||||
expect(collisions.components).toEqual([]);
|
||||
expect(collisions.modules).toEqual([]);
|
||||
expect(collisions.variants).toEqual([]);
|
||||
expect(collisions.styles).toEqual({
|
||||
colors: [],
|
||||
text: []
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('can import project with files', function (done) {
|
||||
var tempDir = App.getPath('temp') + '/noodlunittests-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectory(tempDir, function (r) {
|
||||
if (r.result !== 'success') {
|
||||
throw 'gaah';
|
||||
}
|
||||
|
||||
ncp(Process.cwd() + '/tests/testfs/import_proj1', tempDir + '/import_proj1', function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
projectFromDirectory(tempDir + '/import_proj1', function (project) {
|
||||
ProjectModel.instance = project;
|
||||
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj3',
|
||||
function (imports) {
|
||||
ProjectImporter.instance.import(Process.cwd() + '/tests/testfs/import_proj3', imports, function () {
|
||||
expect(ProjectModel.instance.getComponentWithName('/Main2')).not.toBe(undefined);
|
||||
|
||||
// Check that files have been copied properly
|
||||
expectFilesToExist(
|
||||
tempDir + '/import_proj1',
|
||||
['assets/bear.jpg', 'Fontfabric - Nexa-Bold.otf', 'newfile.jpg'],
|
||||
function (success) {
|
||||
expect(success).toBe(true);
|
||||
done();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can import project with styles, variants and modules', function (done) {
|
||||
var tempDir = App.getPath('temp') + '/noodlunittests-' + Utils.guid() + '/';
|
||||
FileSystem.instance.makeDirectory(tempDir, function (r) {
|
||||
if (r.result !== 'success') {
|
||||
throw 'gaah';
|
||||
}
|
||||
|
||||
ncp(Process.cwd() + '/tests/testfs/import_proj1', tempDir + '/import_proj1', function (err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
projectFromDirectory(tempDir + '/import_proj1', function (project) {
|
||||
ProjectModel.instance = project;
|
||||
|
||||
ProjectImporter.instance.listComponentsAndDependencies(
|
||||
Process.cwd() + '/tests/testfs/import_proj5',
|
||||
function (imports) {
|
||||
ProjectImporter.instance.import(Process.cwd() + '/tests/testfs/import_proj5', imports, function () {
|
||||
const styles = ProjectModel.instance.getMetaData('styles');
|
||||
expect(Object.keys(styles.colors).sort()).toEqual([
|
||||
'Dark',
|
||||
'Dark Gray',
|
||||
'Light Gray',
|
||||
'Primary',
|
||||
'Primary Dark',
|
||||
'Primary Light'
|
||||
]);
|
||||
expect(Object.keys(styles.text).sort()).toEqual(['Body Text', 'Button Label', 'Label Text']);
|
||||
|
||||
expect(
|
||||
ProjectModel.instance.findVariant('Basic', {
|
||||
localName: 'net.noodl.controls.button'
|
||||
})
|
||||
).not.toBe(undefined);
|
||||
expect(
|
||||
ProjectModel.instance.findVariant('Search Field', {
|
||||
localName: 'net.noodl.controls.textinput'
|
||||
})
|
||||
).not.toBe(undefined);
|
||||
|
||||
expect(fs.existsSync(tempDir + '/import_proj1/noodl_modules/material-icons')).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('ignores .git', function (done) {
|
||||
const path = Process.cwd() + '/tests/testfs/import_proj4/';
|
||||
|
||||
//add a .git folder with a file inside
|
||||
FileSystem.instance.makeDirectorySync(path + '.git');
|
||||
FileSystem.instance.writeFileSync(path + '.git/test', 'test');
|
||||
|
||||
ProjectImporter.instance.listComponentsAndDependencies(path, (imports) => {
|
||||
expect(imports.components.length).toBe(1);
|
||||
expect(imports.resources.length).toBe(0);
|
||||
|
||||
//remove the .git folder
|
||||
FileSystem.instance.removeFileSync(path + '.git/test');
|
||||
FileSystem.instance.removeDirectoryRecursiveSync(path + '.git');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
175
packages/noodl-editor/tests/project/projectmodel.js
Normal file
@@ -0,0 +1,175 @@
|
||||
const NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
const { ProjectModel } = require('@noodl-models/projectmodel');
|
||||
const WarningsModel = require('@noodl-models/warningsmodel').WarningsModel;
|
||||
|
||||
describe('Project model tests', function () {
|
||||
it('can upgrade from 0 to 1', function () {
|
||||
var p = ProjectModel.fromJSON(project0);
|
||||
|
||||
// Project upgrader from 0 to 1 should replace = types with * types
|
||||
var json = JSON.stringify(p.toJSON());
|
||||
expect(json.indexOf('=')).toBe(-1);
|
||||
expect(json.match(/\*/g).length).toBe(2);
|
||||
});
|
||||
|
||||
xit('can apply patch', function () {
|
||||
var p = ProjectModel.fromJSON(project1);
|
||||
|
||||
// Apply patch
|
||||
p.applyPatch({
|
||||
askPermission: false,
|
||||
notifyUser: false,
|
||||
nodePatches: [
|
||||
{
|
||||
nodeId: 'A',
|
||||
typename: 'group',
|
||||
version: 3,
|
||||
params: {
|
||||
x: 20,
|
||||
alignX: null,
|
||||
alignY: 'top'
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(p.findNodeWithId('A').type instanceof NodeLibrary.BasicNodeType).toBe(true);
|
||||
expect(p.findNodeWithId('A').type.name).toBe('group');
|
||||
expect(p.findNodeWithId('A').version).toBe(3);
|
||||
expect(p.findNodeWithId('A').getParameter('x')).toBe(20);
|
||||
expect(p.findNodeWithId('A').getParameter('alignX')).toBe(undefined);
|
||||
expect(p.findNodeWithId('A').getParameter('alignY')).toBe('top');
|
||||
|
||||
// Ask permission, should not apply patch immediately
|
||||
p.applyPatch({
|
||||
key: 'a',
|
||||
askPermission: true,
|
||||
notifyUser: false,
|
||||
nodePatches: [
|
||||
{
|
||||
nodeId: 'A',
|
||||
params: {
|
||||
alignY: 'bottom'
|
||||
}
|
||||
}
|
||||
],
|
||||
dismissPatches: [
|
||||
{
|
||||
nodeId: 'A',
|
||||
params: {
|
||||
alignY: null
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(WarningsModel.instance.warnings['/']['/']['patch-a']).not.toBe(undefined); // Warnings should be generated
|
||||
expect(p.findNodeWithId('A').getParameter('alignY')).toBe('top');
|
||||
|
||||
// Emulate user clicking patch
|
||||
WarningsModel.instance.warnings['/']['/']['patch-a'].warning.onPatch();
|
||||
expect(p.findNodeWithId('A').getParameter('alignY')).toBe('bottom');
|
||||
|
||||
// Ask permission, should not apply patch immediately
|
||||
p.applyPatch({
|
||||
key: 'a',
|
||||
askPermission: true,
|
||||
notifyUser: false,
|
||||
nodePatches: [],
|
||||
dismissPatches: [
|
||||
{
|
||||
nodeId: 'A',
|
||||
params: {
|
||||
alignY: null
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Emulate user clicking dismiss
|
||||
WarningsModel.instance.warnings['/']['/']['patch-a'].warning.onDismiss();
|
||||
expect(p.findNodeWithId('A').getParameter('alignY')).toBe(undefined);
|
||||
});
|
||||
|
||||
xit('can apply settings patch', function () {
|
||||
var p = ProjectModel.fromJSON(project1);
|
||||
|
||||
p.applyPatch({
|
||||
askPermission: false,
|
||||
notifyUser: false,
|
||||
settingsPatch: {
|
||||
s1: null,
|
||||
s2: 'Wohoo'
|
||||
}
|
||||
});
|
||||
|
||||
expect(p.getSettings().s1).toBe(undefined);
|
||||
expect(p.getSettings().s2).toBe('Wohoo');
|
||||
});
|
||||
|
||||
// Project that should be patched
|
||||
var project1 = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'A',
|
||||
type: 'image',
|
||||
parameters: {
|
||||
x: 10,
|
||||
alignX: 'left'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
settings: {
|
||||
s1: 'Hello'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Old project model that should be upgraded
|
||||
var project0 = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'ES-1',
|
||||
type: 'Event Sender',
|
||||
ports: [
|
||||
{
|
||||
type: '=',
|
||||
name: 'a port'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'comp2',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
id: 'ES-1',
|
||||
type: 'Event Sender',
|
||||
ports: [
|
||||
{
|
||||
type: {
|
||||
name: '='
|
||||
},
|
||||
name: 'a port'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
47
packages/noodl-editor/tests/project/projectvalidator.js
Normal file
@@ -0,0 +1,47 @@
|
||||
var ProjectValidator = require('@noodl-utils/projectvalidator');
|
||||
|
||||
// Project settings
|
||||
describe('Project validator', function () {
|
||||
it('can validate missing components', function () {
|
||||
const proj = {};
|
||||
|
||||
const validator = new ProjectValidator();
|
||||
validator.validate(proj);
|
||||
expect(validator.hasErrors()).toBe(true);
|
||||
expect(validator.errors[0].msg).toBe('Project is missing name');
|
||||
expect(validator.errors[1].msg).toBe('Project is missing components');
|
||||
});
|
||||
|
||||
it('can validate dangling connections and fix', function () {
|
||||
const proj = {
|
||||
name: 'C',
|
||||
components: [
|
||||
{
|
||||
name: 'A',
|
||||
graph: {
|
||||
roots: [],
|
||||
connections: [
|
||||
{
|
||||
fromId: 'a',
|
||||
fromProperty: 'hej',
|
||||
toId: 'b',
|
||||
toProperty: 'hej'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const validator = new ProjectValidator();
|
||||
validator.validate(proj);
|
||||
expect(validator.hasErrors()).toBe(true);
|
||||
expect(validator.errors[0].msg).toBe('Dangling connection at A missing source missing target ');
|
||||
|
||||
validator.fix();
|
||||
validator.clearErrors();
|
||||
validator.validate(proj);
|
||||
expect(validator.hasErrors()).toBe(false);
|
||||
expect(proj.components[0].graph.connections.length).toBe(0);
|
||||
});
|
||||
});
|
||||
5
packages/noodl-editor/tests/projectmerger/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './projectmerger-comments';
|
||||
export * from './projectmerger-diff';
|
||||
export * from './projectmerger-states';
|
||||
export * from './projectmerger-variants';
|
||||
export * from './projectmerger';
|
||||
@@ -0,0 +1,302 @@
|
||||
var ProjectMerger = require('@noodl-utils/projectmerger');
|
||||
|
||||
function mergeComments(base, ours, theirs) {
|
||||
const baseComponent = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [],
|
||||
comments: base
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const ourComponent = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [],
|
||||
comments: ours
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const theirComponent = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [],
|
||||
comments: theirs
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return ProjectMerger.mergeProject(baseComponent, ourComponent, theirComponent);
|
||||
}
|
||||
// Project settings
|
||||
describe('Project merger - comments', function () {
|
||||
it('can merge new comments', function () {
|
||||
const ours = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const theirs = [
|
||||
{
|
||||
id: 'c2',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const res = mergeComments(undefined, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
},
|
||||
{
|
||||
id: 'c2',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('can merge updated comments - theirs updated', function () {
|
||||
const base = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const ours = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const theirs = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const res = mergeComments(base, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('can merge updated comments - ours updated', function () {
|
||||
const base = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const ours = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const theirs = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const res = mergeComments(base, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('can merge deleted comments - ours deleted', function () {
|
||||
const base = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const ours = [];
|
||||
const theirs = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const res = mergeComments(base, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([]);
|
||||
});
|
||||
|
||||
it('can merge deleted comments - theirs deleted', function () {
|
||||
const base = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const ours = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const theirs = [];
|
||||
const res = mergeComments(base, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([]);
|
||||
});
|
||||
|
||||
it('can merge deleted and changed comments - ours modified, theirs deleted', function () {
|
||||
const base = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const ours = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const theirs = [];
|
||||
const res = mergeComments(base, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('can merge deleted and changed comments - ours deleted, theirs modified', function () {
|
||||
const base = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hej',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const ours = [];
|
||||
const theirs = [
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
];
|
||||
const res = mergeComments(base, ours, theirs);
|
||||
|
||||
expect(res.components[0].graph.comments).toEqual([
|
||||
{
|
||||
id: 'c1',
|
||||
text: 'hopp',
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
155
packages/noodl-editor/tests/projectmerger/projectmerger-diff.js
Normal file
@@ -0,0 +1,155 @@
|
||||
var { diffProject } = require('@noodl-utils/projectmerger.diff');
|
||||
var fs = require('fs');
|
||||
var Process = require('process');
|
||||
|
||||
// Project settings
|
||||
describe('Project merger diff', function () {
|
||||
it('can diff two identical projects without reporting any changes', function () {
|
||||
const base = JSON.parse(
|
||||
fs.readFileSync(
|
||||
Process.cwd() + '/tests/testfs/merge-tests/move-nodes/base-merge-project-Wed--03-Feb-2021-11-07-55-GMT.json'
|
||||
)
|
||||
);
|
||||
const diff = diffProject(base, base);
|
||||
|
||||
expect(diff.components.changed.length).toBe(0, 'no changed components');
|
||||
expect(diff.components.created.length).toBe(0, 'no created components');
|
||||
expect(diff.components.deleted.length).toBe(0, 'no deleted components');
|
||||
expect(diff.components.unchanged.length).toBe(base.components.length, 'all components unchanged');
|
||||
});
|
||||
|
||||
it('can diff with one node changes', function () {
|
||||
const base = JSON.parse(
|
||||
fs.readFileSync(
|
||||
Process.cwd() + '/tests/testfs/merge-tests/move-nodes/base-merge-project-Wed--03-Feb-2021-11-07-55-GMT.json'
|
||||
)
|
||||
);
|
||||
const current = JSON.parse(JSON.stringify(base));
|
||||
|
||||
//modify a text node
|
||||
current.components[0].graph.roots[0].children[0].parameters.text = 'Hello 2';
|
||||
|
||||
const diff = diffProject(base, current);
|
||||
|
||||
expect(diff.components.changed.length).toBe(1, 'should have one changed component');
|
||||
expect(diff.components.created.length).toBe(0, 'no created components');
|
||||
expect(diff.components.deleted.length).toBe(0, 'no deleted components');
|
||||
expect(diff.components.unchanged.length).toBe(base.components.length - 1);
|
||||
});
|
||||
|
||||
it('diff ignores metadata', function () {
|
||||
const base = JSON.parse(
|
||||
fs.readFileSync(
|
||||
Process.cwd() + '/tests/testfs/merge-tests/move-nodes/base-merge-project-Wed--03-Feb-2021-11-07-55-GMT.json'
|
||||
)
|
||||
);
|
||||
const current = JSON.parse(JSON.stringify(base));
|
||||
|
||||
// change metadata in component
|
||||
current.components[0].metadata.canvasPos.x = 50;
|
||||
current.components[0].graph.roots[0].dynamicports = [
|
||||
{
|
||||
name: 'testy',
|
||||
type: 'string'
|
||||
}
|
||||
];
|
||||
|
||||
//change metadata in node
|
||||
current.components[0].graph.roots[0].metadata = {
|
||||
sourceCodePorts: ['test']
|
||||
};
|
||||
|
||||
const diff = diffProject(base, current);
|
||||
|
||||
expect(diff.components.changed.length).toBe(0, 'no changed components');
|
||||
expect(diff.components.created.length).toBe(0, 'no created components');
|
||||
expect(diff.components.deleted.length).toBe(0, 'no deleted components');
|
||||
expect(diff.components.unchanged.length).toBe(base.components.length, 'all components unchanged');
|
||||
});
|
||||
|
||||
it('can diff variants', function () {
|
||||
const base = {
|
||||
components: [],
|
||||
variants: [
|
||||
{
|
||||
name: 'A',
|
||||
typename: 'A',
|
||||
parameters: {
|
||||
p1: 10
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'A',
|
||||
typename: 'B',
|
||||
parameters: {
|
||||
p1: 'test'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'C',
|
||||
typename: 'C',
|
||||
parameters: {
|
||||
p1: 10
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
const current = {
|
||||
components: [],
|
||||
variants: [
|
||||
{
|
||||
name: 'A',
|
||||
typename: 'A',
|
||||
parameters: {
|
||||
p2: 20
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'B',
|
||||
typename: 'A',
|
||||
parameters: {
|
||||
p1: 'test'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'C',
|
||||
typename: 'C',
|
||||
parameters: {
|
||||
p1: 10
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const diff = diffProject(base, current);
|
||||
|
||||
expect(diff.variants.changed.length).toBe(1);
|
||||
expect(diff.variants.created.length).toBe(1);
|
||||
expect(diff.variants.unchanged.length).toBe(1);
|
||||
});
|
||||
|
||||
it('can diff settings', function () {
|
||||
const base = {
|
||||
components: [],
|
||||
settings: {
|
||||
htmlTitle: 'A',
|
||||
headCode: 'lolol',
|
||||
someSetting: 'abc'
|
||||
}
|
||||
};
|
||||
const current = {
|
||||
components: [],
|
||||
settings: {
|
||||
htmlTitle: 'B',
|
||||
bodyScroll: true,
|
||||
someSetting: 'abc'
|
||||
}
|
||||
};
|
||||
const diff = diffProject(base, current);
|
||||
|
||||
expect(diff.settings.changed.length).toBe(1);
|
||||
expect(diff.settings.created.length).toBe(1);
|
||||
expect(diff.settings.deleted.length).toBe(1);
|
||||
expect(diff.settings.unchanged.length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,557 @@
|
||||
var ProjectMerger = require('@noodl-utils/projectmerger');
|
||||
var NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
var fs = require('fs');
|
||||
var Process = require('process');
|
||||
|
||||
// Project settings
|
||||
describe('Project merger (states and transitions)', function () {
|
||||
it('can merge add state transitions to empty ancestor', function () {
|
||||
var a = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A'
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
stateParameters: {
|
||||
hover: {
|
||||
p1: 'changed'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A'
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
expect(res.components[0].graph.roots[0]).toEqual({
|
||||
type: '0',
|
||||
id: 'A',
|
||||
stateParameters: {
|
||||
hover: {
|
||||
p1: 'changed'
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('can merge state parameters', function () {
|
||||
var a = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {},
|
||||
stateParameters: {
|
||||
hover: {
|
||||
p1: 'some-string',
|
||||
p3: 'remove-me'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
stateParameters: {
|
||||
hover: {
|
||||
p1: 'changed',
|
||||
p2: 'added-string',
|
||||
p3: 'remove-me'
|
||||
},
|
||||
pressed: {
|
||||
p4: 'new-param'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {},
|
||||
stateParameters: {
|
||||
hover: {
|
||||
p1: 10 // Should conflict
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
expect(res.components[0].graph.roots[0]).toEqual({
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: undefined,
|
||||
stateParameters: {
|
||||
hover: {
|
||||
p1: 'changed',
|
||||
p2: 'added-string',
|
||||
p3: undefined
|
||||
},
|
||||
pressed: {
|
||||
p4: 'new-param'
|
||||
}
|
||||
},
|
||||
ports: [],
|
||||
conflicts: [
|
||||
{
|
||||
type: 'stateParameter',
|
||||
state: 'hover',
|
||||
name: 'p1',
|
||||
ours: 'changed',
|
||||
theirs: 10
|
||||
}
|
||||
],
|
||||
children: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('can merge add state transitions to empty ancestor', function () {
|
||||
var a = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: 'changed'
|
||||
},
|
||||
p2: {
|
||||
dur: 0,
|
||||
curve: 'added'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
expect(res.components[0].graph.roots[0]).toEqual({
|
||||
type: '0',
|
||||
id: 'A',
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: 'changed'
|
||||
},
|
||||
p2: {
|
||||
dur: 0,
|
||||
curve: 'added'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('can merge state transitions', function () {
|
||||
var a = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {},
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: [1, 1, 1, 1]
|
||||
},
|
||||
p3: 'remove-me'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: 'changed'
|
||||
},
|
||||
p2: {
|
||||
dur: 0,
|
||||
curve: 'added'
|
||||
},
|
||||
p3: 'remove-me'
|
||||
},
|
||||
pressed: {
|
||||
p4: {
|
||||
dur: 0,
|
||||
curve: [0, 1, 0, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {},
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
expect(res.components[0].graph.roots[0]).toEqual({
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: undefined,
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: 'changed'
|
||||
},
|
||||
p2: {
|
||||
dur: 0,
|
||||
curve: 'added'
|
||||
},
|
||||
p3: undefined
|
||||
},
|
||||
pressed: {
|
||||
p4: {
|
||||
dur: 0,
|
||||
curve: [0, 1, 0, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
ports: [],
|
||||
conflicts: [
|
||||
{
|
||||
type: 'stateTransition',
|
||||
state: 'hover',
|
||||
name: 'p1',
|
||||
ours: {
|
||||
dur: 0,
|
||||
curve: 'changed'
|
||||
},
|
||||
theirs: {
|
||||
dur: 0,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
],
|
||||
children: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('can merge default state transitions', function () {
|
||||
var a = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
defaultStateTransitions: {
|
||||
neutral: {
|
||||
dur: 100,
|
||||
curve: [0, 0, 1, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {},
|
||||
defaultStateTransitions: {
|
||||
neutral: {
|
||||
dur: 200,
|
||||
curve: [1, 1, 1, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
expect(res.components[0].graph.roots[0]).toEqual({
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: undefined,
|
||||
defaultStateTransitions: {
|
||||
neutral: {
|
||||
dur: 100,
|
||||
curve: [0, 0, 1, 1]
|
||||
}
|
||||
},
|
||||
ports: [],
|
||||
conflicts: [
|
||||
{
|
||||
type: 'defaultStateTransition',
|
||||
state: 'neutral',
|
||||
ours: {
|
||||
dur: 100,
|
||||
curve: [0, 0, 1, 1]
|
||||
},
|
||||
theirs: {
|
||||
dur: 200,
|
||||
curve: [1, 1, 1, 1]
|
||||
}
|
||||
}
|
||||
],
|
||||
children: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('can merge variant', function () {
|
||||
var a = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {}
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
variant: 'VariantA'
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [
|
||||
{
|
||||
name: 'comp1',
|
||||
graph: {
|
||||
roots: [
|
||||
{
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: {},
|
||||
variant: 'VariantB'
|
||||
}
|
||||
],
|
||||
connections: []
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
expect(res.components[0].graph.roots[0]).toEqual({
|
||||
type: '0',
|
||||
id: 'A',
|
||||
parameters: undefined,
|
||||
variant: 'VariantA',
|
||||
ports: [],
|
||||
conflicts: [
|
||||
{
|
||||
type: 'variant',
|
||||
ours: 'VariantA',
|
||||
theirs: 'VariantB'
|
||||
}
|
||||
],
|
||||
children: undefined
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
var ProjectMerger = require('@noodl-utils/projectmerger');
|
||||
var NodeLibrary = require('@noodl-models/nodelibrary').NodeLibrary;
|
||||
var fs = require('fs');
|
||||
var Process = require('process');
|
||||
|
||||
// Project settings
|
||||
describe('Project merger (variants)', function () {
|
||||
it('can merge variants (conflicts)', function () {
|
||||
var a = {
|
||||
components: [],
|
||||
variants: [
|
||||
{
|
||||
typename: 'Group',
|
||||
name: 'A',
|
||||
parameters: {
|
||||
test: 'hej'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var o = {
|
||||
components: [],
|
||||
variants: [
|
||||
{
|
||||
typename: 'Group',
|
||||
name: 'A',
|
||||
parameters: {
|
||||
test: 'hej2'
|
||||
},
|
||||
stateParameters: {
|
||||
hover: {
|
||||
test: 'a'
|
||||
}
|
||||
},
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 500,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultStateTransitions: {
|
||||
hover: {
|
||||
dur: 500,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
var t = {
|
||||
components: [],
|
||||
variants: [
|
||||
{
|
||||
typename: 'Group',
|
||||
name: 'A',
|
||||
parameters: {
|
||||
test: 'hej3'
|
||||
},
|
||||
stateParameters: {
|
||||
hover: {
|
||||
test: 'b'
|
||||
}
|
||||
},
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 0,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultStateTransitions: {
|
||||
hover: {
|
||||
dur: 0,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var res = ProjectMerger.mergeProject(a, o, t);
|
||||
console.log(res);
|
||||
expect(res.variants[0]).toEqual({
|
||||
typename: 'Group',
|
||||
name: 'A',
|
||||
parameters: {
|
||||
test: 'hej2'
|
||||
},
|
||||
stateParameters: {
|
||||
hover: {
|
||||
test: 'a'
|
||||
}
|
||||
},
|
||||
stateTransitions: {
|
||||
hover: {
|
||||
p1: {
|
||||
dur: 500,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultStateTransitions: {
|
||||
hover: {
|
||||
dur: 500,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
},
|
||||
conflicts: [
|
||||
{
|
||||
type: 'parameter',
|
||||
name: 'test',
|
||||
ours: 'hej2',
|
||||
theirs: 'hej3'
|
||||
},
|
||||
{
|
||||
type: 'stateParameter',
|
||||
state: 'hover',
|
||||
name: 'test',
|
||||
ours: 'a',
|
||||
theirs: 'b'
|
||||
},
|
||||
{
|
||||
type: 'stateTransition',
|
||||
state: 'hover',
|
||||
name: 'p1',
|
||||
ours: {
|
||||
dur: 500,
|
||||
curve: [0, 0, 0, 1]
|
||||
},
|
||||
theirs: {
|
||||
dur: 0,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'defaultStateTransition',
|
||||
state: 'hover',
|
||||
ours: {
|
||||
dur: 500,
|
||||
curve: [0, 0, 0, 1]
|
||||
},
|
||||
theirs: {
|
||||
dur: 0,
|
||||
curve: [0, 0, 0, 1]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
1500
packages/noodl-editor/tests/projectmerger/projectmerger.js
Normal file
1
packages/noodl-editor/tests/projectpatcher/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './projectpatcher-events';
|
||||
@@ -0,0 +1,88 @@
|
||||
import { applyPatches } from '@noodl-models/ProjectPatches/applypatches';
|
||||
|
||||
// Project settings
|
||||
describe('Project patcher - events', function () {
|
||||
it('can patch send event nodes', function () {
|
||||
const project = {
|
||||
"name": "event-patcher-test",
|
||||
"components": [
|
||||
{
|
||||
"name": "/App",
|
||||
"graph": {
|
||||
"connections": [
|
||||
],
|
||||
"roots": [
|
||||
{
|
||||
"id": "4143a274-208c-debf-bd59-e399e0f8ee82",
|
||||
"type": "Event Sender",
|
||||
"x": -327.46819153012916,
|
||||
"y": 305.4376377651178,
|
||||
"parameters": {
|
||||
"channelName": "achannel"
|
||||
},
|
||||
"ports": [
|
||||
{
|
||||
"name": "One",
|
||||
"plug": "input",
|
||||
"type": {
|
||||
"name": "*",
|
||||
"allowConnectionOnly": true
|
||||
},
|
||||
"group": "Payload",
|
||||
"index": 1
|
||||
},
|
||||
{
|
||||
"name": "Two",
|
||||
"plug": "input",
|
||||
"type": {
|
||||
"name": "*",
|
||||
"allowConnectionOnly": true
|
||||
},
|
||||
"group": "Payload",
|
||||
"index": 2
|
||||
}
|
||||
],
|
||||
"dynamicports": [],
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const after = {
|
||||
"name": "event-patcher-test",
|
||||
"components": [
|
||||
{
|
||||
"name": "/App",
|
||||
"graph": {
|
||||
"connections": [
|
||||
],
|
||||
"roots": [
|
||||
{
|
||||
"id": "4143a274-208c-debf-bd59-e399e0f8ee82",
|
||||
"type": "Event Sender",
|
||||
"x": -327.46819153012916,
|
||||
"y": 305.4376377651178,
|
||||
"parameters": {
|
||||
"channelName": "achannel",
|
||||
"payload": "One,Two"
|
||||
},
|
||||
"ports": [],
|
||||
"dynamicports": [
|
||||
],
|
||||
"children": []
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
applyPatches(project)
|
||||
|
||||
expect(project).toEqual(after)
|
||||
})
|
||||
|
||||
});
|
||||
261
packages/noodl-editor/tests/recordings/connectiondebugger.json
Normal file
@@ -0,0 +1,261 @@
|
||||
[
|
||||
{ "type": "over", "time": 1439213679751, "x": 79, "y": 332, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679752, "x": 79, "y": 332, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679765, "x": 135, "y": 334, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679783, "x": 157, "y": 334, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679810, "x": 162, "y": 334, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679852, "x": 162, "y": 335, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679869, "x": 159, "y": 338, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679886, "x": 159, "y": 344, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679925, "x": 159, "y": 354, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679937, "x": 163, "y": 363, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679954, "x": 173, "y": 381, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679972, "x": 192, "y": 409, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213679989, "x": 208, "y": 426, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680005, "x": 222, "y": 431, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680022, "x": 228, "y": 432, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680039, "x": 238, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680056, "x": 246, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680074, "x": 254, "y": 433, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680092, "x": 258, "y": 432, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680109, "x": 260, "y": 432, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680126, "x": 262, "y": 431, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680144, "x": 263, "y": 431, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213680172, "x": 263, "y": 431, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680180, "x": 263, "y": 430, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680198, "x": 263, "y": 427, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680228, "x": 263, "y": 419, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680230, "x": 261, "y": 403, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680248, "x": 255, "y": 378, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680265, "x": 246, "y": 338, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680281, "x": 224, "y": 278, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680299, "x": 199, "y": 219, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680316, "x": 181, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680337, "x": 166, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680349, "x": 158, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680366, "x": 153, "y": 118, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680570, "x": 127, "y": 62, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680572, "x": 126, "y": 60, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213680588, "x": 126, "y": 60, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680589, "x": 125, "y": 59, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680668, "x": 125, "y": 60, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680685, "x": 122, "y": 69, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680702, "x": 119, "y": 79, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680719, "x": 117, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680737, "x": 117, "y": 96, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680754, "x": 116, "y": 99, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680772, "x": 116, "y": 100, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680807, "x": 115, "y": 101, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680837, "x": 115, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680854, "x": 115, "y": 104, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680871, "x": 112, "y": 107, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680889, "x": 111, "y": 111, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680906, "x": 110, "y": 116, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680923, "x": 110, "y": 118, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680941, "x": 110, "y": 120, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680964, "x": 110, "y": 121, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680981, "x": 109, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213680998, "x": 109, "y": 123, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681016, "x": 108, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681033, "x": 107, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681051, "x": 107, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213681068, "x": 107, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681108, "x": 108, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681125, "x": 111, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681142, "x": 117, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681159, "x": 123, "y": 113, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681180, "x": 130, "y": 108, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681197, "x": 135, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681212, "x": 140, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681229, "x": 143, "y": 99, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681247, "x": 145, "y": 97, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681264, "x": 148, "y": 96, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681281, "x": 150, "y": 94, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681298, "x": 152, "y": 94, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681314, "x": 154, "y": 92, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681331, "x": 155, "y": 91, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681348, "x": 158, "y": 90, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681364, "x": 159, "y": 89, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681381, "x": 160, "y": 89, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213681564, "x": 160, "y": 89, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681643, "x": 160, "y": 90, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681660, "x": 162, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681677, "x": 167, "y": 103, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681694, "x": 176, "y": 112, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681715, "x": 190, "y": 123, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681731, "x": 202, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681751, "x": 217, "y": 138, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681764, "x": 233, "y": 145, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681781, "x": 243, "y": 149, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681814, "x": 249, "y": 152, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681816, "x": 258, "y": 154, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681832, "x": 260, "y": 154, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681849, "x": 263, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681866, "x": 266, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681883, "x": 269, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681900, "x": 275, "y": 159, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681917, "x": 281, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681934, "x": 285, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681953, "x": 287, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213681968, "x": 288, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213681982, "x": 288, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213682060, "x": 288, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682141, "x": 268, "y": 184, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682159, "x": 268, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682459, "x": 269, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682476, "x": 270, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682598, "x": 259, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682600, "x": 246, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682637, "x": 221, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682651, "x": 214, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682669, "x": 208, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682686, "x": 201, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682703, "x": 192, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682720, "x": 185, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682737, "x": 175, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682755, "x": 168, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682772, "x": 165, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682789, "x": 164, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682806, "x": 162, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213682878, "x": 162, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682879, "x": 163, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682893, "x": 168, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682912, "x": 181, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682928, "x": 206, "y": 171, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682947, "x": 235, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682963, "x": 264, "y": 161, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682978, "x": 291, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213682998, "x": 313, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683014, "x": 326, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683033, "x": 337, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683053, "x": 347, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683066, "x": 356, "y": 120, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683081, "x": 363, "y": 114, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683098, "x": 370, "y": 109, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683114, "x": 373, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683131, "x": 375, "y": 104, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683148, "x": 376, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683388, "x": 375, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683416, "x": 373, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683429, "x": 372, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683448, "x": 371, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213683700, "x": 371, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683796, "x": 371, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683826, "x": 370, "y": 104, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683829, "x": 367, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683850, "x": 360, "y": 114, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683865, "x": 350, "y": 123, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683885, "x": 333, "y": 138, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683898, "x": 312, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683915, "x": 286, "y": 182, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213683933, "x": 261, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684058, "x": 205, "y": 256, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684069, "x": 200, "y": 257, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684086, "x": 198, "y": 258, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684103, "x": 196, "y": 260, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684120, "x": 194, "y": 262, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684145, "x": 192, "y": 262, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684155, "x": 191, "y": 263, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684172, "x": 188, "y": 263, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684189, "x": 188, "y": 264, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684206, "x": 187, "y": 265, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684228, "x": 186, "y": 265, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684284, "x": 186, "y": 266, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213684564, "x": 186, "y": 266, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684604, "x": 186, "y": 265, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684621, "x": 186, "y": 262, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684638, "x": 186, "y": 257, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684655, "x": 186, "y": 252, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684680, "x": 186, "y": 246, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684689, "x": 186, "y": 242, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684707, "x": 186, "y": 239, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684724, "x": 186, "y": 236, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684740, "x": 186, "y": 234, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684758, "x": 186, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684774, "x": 186, "y": 230, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684791, "x": 186, "y": 229, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684812, "x": 186, "y": 228, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684829, "x": 186, "y": 227, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684845, "x": 186, "y": 226, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684863, "x": 186, "y": 224, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684879, "x": 186, "y": 223, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684895, "x": 186, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213684924, "x": 186, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213685004, "x": 186, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685116, "x": 187, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685133, "x": 188, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685150, "x": 192, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685166, "x": 205, "y": 217, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685183, "x": 216, "y": 212, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685201, "x": 230, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685218, "x": 242, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685235, "x": 251, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685253, "x": 257, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685270, "x": 261, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685287, "x": 263, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685310, "x": 265, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685325, "x": 266, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685342, "x": 266, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685365, "x": 267, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685381, "x": 270, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685399, "x": 276, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685415, "x": 279, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685432, "x": 280, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685450, "x": 281, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213685524, "x": 282, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686036, "x": 282, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686053, "x": 282, "y": 184, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686071, "x": 282, "y": 183, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686088, "x": 282, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686105, "x": 282, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686122, "x": 283, "y": 177, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686139, "x": 283, "y": 174, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686180, "x": 281, "y": 169, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686190, "x": 280, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686221, "x": 280, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686252, "x": 280, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213686500, "x": 280, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213686596, "x": 280, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686788, "x": 280, "y": 164, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686806, "x": 280, "y": 161, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686822, "x": 280, "y": 152, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686839, "x": 277, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686857, "x": 276, "y": 140, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686874, "x": 275, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686890, "x": 275, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686908, "x": 275, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686924, "x": 275, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686941, "x": 275, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213686965, "x": 275, "y": 118, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687004, "x": 275, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687043, "x": 275, "y": 116, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687099, "x": 275, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687118, "x": 275, "y": 114, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687134, "x": 275, "y": 112, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687151, "x": 275, "y": 111, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687169, "x": 276, "y": 111, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687628, "x": 276, "y": 110, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687645, "x": 276, "y": 109, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687665, "x": 276, "y": 108, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687681, "x": 276, "y": 107, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687698, "x": 276, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687715, "x": 276, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687735, "x": 276, "y": 103, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687751, "x": 277, "y": 101, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687766, "x": 278, "y": 100, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687784, "x": 278, "y": 98, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687802, "x": 278, "y": 97, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213687819, "x": 278, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439213688116, "x": 278, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439213688227, "x": 278, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688768, "x": 277, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688782, "x": 267, "y": 99, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688800, "x": 246, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688816, "x": 223, "y": 109, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688832, "x": 198, "y": 116, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688848, "x": 167, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688866, "x": 133, "y": 133, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688905, "x": 55, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439213688917, "x": 15, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1439213688935, "x": -17, "y": 175, "evt": { "button": 0 } }
|
||||
]
|
||||
223
packages/noodl-editor/tests/recordings/cutnpaste.json
Normal file
@@ -0,0 +1,223 @@
|
||||
[
|
||||
{ "type": "over", "time": 1454322937752, "x": 67, "y": 408, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322937754, "x": 67, "y": 408, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322937767, "x": 152, "y": 420, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322937784, "x": 205, "y": 431, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322937801, "x": 223, "y": 437, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322937818, "x": 224, "y": 439, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322937836, "x": 225, "y": 440, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938035, "x": 225, "y": 440, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938052, "x": 226, "y": 441, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938068, "x": 227, "y": 441, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938085, "x": 235, "y": 442, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938102, "x": 255, "y": 442, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938120, "x": 266, "y": 439, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938137, "x": 268, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938154, "x": 268, "y": 433, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938171, "x": 268, "y": 429, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938189, "x": 267, "y": 426, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938206, "x": 265, "y": 423, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938223, "x": 264, "y": 420, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938240, "x": 261, "y": 418, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1454322938243, "x": 261, "y": 418, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938258, "x": 261, "y": 417, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938275, "x": 260, "y": 416, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938292, "x": 259, "y": 414, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938314, "x": 255, "y": 411, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938327, "x": 248, "y": 402, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938343, "x": 235, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938361, "x": 220, "y": 375, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938378, "x": 204, "y": 360, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938396, "x": 186, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938413, "x": 172, "y": 331, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938431, "x": 160, "y": 320, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938449, "x": 150, "y": 309, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938464, "x": 140, "y": 299, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938482, "x": 130, "y": 288, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938500, "x": 118, "y": 277, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938517, "x": 109, "y": 267, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938533, "x": 98, "y": 258, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938550, "x": 90, "y": 250, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938567, "x": 81, "y": 242, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938584, "x": 74, "y": 236, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938600, "x": 67, "y": 228, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938617, "x": 60, "y": 220, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938634, "x": 54, "y": 215, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938651, "x": 50, "y": 211, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938668, "x": 46, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938685, "x": 45, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938702, "x": 43, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938719, "x": 42, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938739, "x": 42, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938756, "x": 41, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938774, "x": 41, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938791, "x": 40, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938809, "x": 39, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938826, "x": 37, "y": 197, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322938844, "x": 36, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1454322939139, "x": 36, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322939162, "x": 35, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "copy", "time": 1454322939962 },
|
||||
{ "type": "paste", "time": 1454322940457 },
|
||||
{ "type": "move", "time": 1454322941043, "x": 35, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941059, "x": 35, "y": 197, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941077, "x": 36, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941093, "x": 36, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941111, "x": 37, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941128, "x": 39, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941144, "x": 41, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941162, "x": 43, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941179, "x": 46, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941196, "x": 51, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941213, "x": 57, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941230, "x": 65, "y": 210, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941247, "x": 74, "y": 212, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941264, "x": 82, "y": 214, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941284, "x": 91, "y": 217, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941298, "x": 102, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941316, "x": 109, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941333, "x": 115, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941350, "x": 120, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941367, "x": 123, "y": 223, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941384, "x": 126, "y": 224, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941401, "x": 130, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941418, "x": 132, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941436, "x": 134, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941454, "x": 135, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941471, "x": 136, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941500, "x": 137, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941516, "x": 138, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941533, "x": 139, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941552, "x": 140, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1454322941739, "x": 140, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941835, "x": 140, "y": 226, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941852, "x": 140, "y": 227, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941869, "x": 140, "y": 228, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941889, "x": 140, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941905, "x": 140, "y": 233, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941922, "x": 140, "y": 236, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941939, "x": 140, "y": 242, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941957, "x": 140, "y": 246, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941974, "x": 140, "y": 252, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322941991, "x": 140, "y": 259, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942008, "x": 140, "y": 267, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942027, "x": 139, "y": 275, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942042, "x": 139, "y": 281, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942060, "x": 139, "y": 287, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942076, "x": 139, "y": 295, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942092, "x": 139, "y": 302, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942109, "x": 139, "y": 309, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942125, "x": 139, "y": 315, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942143, "x": 139, "y": 323, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942160, "x": 139, "y": 328, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942177, "x": 139, "y": 333, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942195, "x": 139, "y": 338, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942211, "x": 139, "y": 342, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942228, "x": 139, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942245, "x": 139, "y": 349, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942262, "x": 139, "y": 352, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942279, "x": 139, "y": 354, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942296, "x": 139, "y": 356, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942314, "x": 139, "y": 361, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942330, "x": 141, "y": 367, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942347, "x": 143, "y": 371, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942364, "x": 143, "y": 375, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942381, "x": 146, "y": 378, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942398, "x": 148, "y": 380, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942416, "x": 149, "y": 383, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942433, "x": 150, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942451, "x": 150, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942468, "x": 151, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942485, "x": 151, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942502, "x": 152, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942520, "x": 152, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942539, "x": 153, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942560, "x": 153, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942594, "x": 153, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942620, "x": 153, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942637, "x": 154, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322942738, "x": 155, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1454322943149, "x": 155, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943314, "x": 156, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943332, "x": 159, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943349, "x": 169, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943366, "x": 187, "y": 382, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943383, "x": 211, "y": 377, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943401, "x": 233, "y": 374, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943419, "x": 256, "y": 367, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943435, "x": 270, "y": 362, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943452, "x": 278, "y": 358, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943469, "x": 281, "y": 357, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943487, "x": 281, "y": 356, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322943516, "x": 281, "y": 355, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1454322944259, "x": 281, "y": 355, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1454322944371, "x": 281, "y": 355, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944507, "x": 281, "y": 357, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944524, "x": 279, "y": 364, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944540, "x": 277, "y": 375, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944557, "x": 274, "y": 392, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944574, "x": 271, "y": 410, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944591, "x": 271, "y": 430, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944609, "x": 273, "y": 451, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944626, "x": 275, "y": 471, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944642, "x": 280, "y": 489, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944660, "x": 286, "y": 499, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944677, "x": 292, "y": 508, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944695, "x": 297, "y": 513, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944712, "x": 301, "y": 517, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944729, "x": 304, "y": 520, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944747, "x": 306, "y": 521, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944766, "x": 306, "y": 522, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944787, "x": 307, "y": 522, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322944986, "x": 306, "y": 522, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945011, "x": 306, "y": 523, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945035, "x": 305, "y": 523, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1454322945050, "x": 305, "y": 523, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945053, "x": 305, "y": 524, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945074, "x": 304, "y": 524, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945086, "x": 303, "y": 524, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945104, "x": 300, "y": 524, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945120, "x": 294, "y": 522, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945138, "x": 280, "y": 516, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945155, "x": 257, "y": 508, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945172, "x": 226, "y": 499, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945189, "x": 189, "y": 490, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945206, "x": 156, "y": 480, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945225, "x": 129, "y": 473, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945240, "x": 105, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945258, "x": 90, "y": 460, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945276, "x": 83, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945292, "x": 75, "y": 455, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945309, "x": 70, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945326, "x": 64, "y": 448, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945343, "x": 56, "y": 443, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945361, "x": 51, "y": 440, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945378, "x": 46, "y": 435, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945395, "x": 41, "y": 431, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945412, "x": 39, "y": 427, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945430, "x": 39, "y": 424, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945446, "x": 39, "y": 421, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945463, "x": 39, "y": 417, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945480, "x": 39, "y": 413, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945498, "x": 37, "y": 410, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945515, "x": 36, "y": 406, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945531, "x": 34, "y": 402, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945549, "x": 32, "y": 399, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945566, "x": 30, "y": 396, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945583, "x": 29, "y": 395, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945602, "x": 29, "y": 394, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945622, "x": 28, "y": 393, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945636, "x": 28, "y": 392, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945659, "x": 28, "y": 391, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945676, "x": 27, "y": 391, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945693, "x": 27, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322945710, "x": 26, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1454322945939, "x": 26, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "cut", "time": 1454322946856 },
|
||||
{ "type": "move", "time": 1454322947698, "x": 25, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322947715, "x": 24, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322947732, "x": 20, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322947749, "x": 11, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1454322947766, "x": 0, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1454322947784, "x": -13, "y": 380, "evt": { "button": 0 } }
|
||||
]
|
||||
63
packages/noodl-editor/tests/recordings/deleteandundo.json
Normal file
@@ -0,0 +1,63 @@
|
||||
[
|
||||
{ "type": "over", "time": 1439214702638, "x": 5, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702638, "x": 5, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702654, "x": 7, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702685, "x": 8, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702778, "x": 8, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702795, "x": 9, "y": 174, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702817, "x": 10, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702830, "x": 13, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702850, "x": 15, "y": 160, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702864, "x": 18, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702882, "x": 21, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702899, "x": 22, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702916, "x": 23, "y": 114, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702933, "x": 23, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702955, "x": 23, "y": 101, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702967, "x": 23, "y": 96, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214702984, "x": 23, "y": 92, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703001, "x": 23, "y": 87, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703019, "x": 23, "y": 83, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703070, "x": 23, "y": 72, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703088, "x": 25, "y": 69, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703105, "x": 25, "y": 65, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703122, "x": 26, "y": 64, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703140, "x": 27, "y": 63, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703160, "x": 28, "y": 62, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703176, "x": 30, "y": 60, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703196, "x": 30, "y": 59, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703210, "x": 31, "y": 59, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439214703317, "x": 31, "y": 59, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703319, "x": 32, "y": 59, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703326, "x": 34, "y": 65, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703344, "x": 40, "y": 77, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703359, "x": 46, "y": 90, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703377, "x": 56, "y": 108, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703395, "x": 66, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703410, "x": 74, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703429, "x": 81, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703457, "x": 86, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703460, "x": 93, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703478, "x": 99, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703495, "x": 104, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703512, "x": 109, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703530, "x": 115, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703548, "x": 119, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703564, "x": 125, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703581, "x": 128, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703598, "x": 130, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703616, "x": 131, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703634, "x": 132, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703652, "x": 133, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703669, "x": 134, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703687, "x": 136, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439214703875, "x": 136, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214703882, "x": 136, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214704043, "x": 136, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214704098, "x": 133, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214704116, "x": 124, "y": 216, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214704133, "x": 103, "y": 234, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214704150, "x": 73, "y": 261, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439214704167, "x": 32, "y": 300, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1439214704185, "x": -20, "y": 352, "evt": { "button": 0 } }
|
||||
]
|
||||
37
packages/noodl-editor/tests/recordings/deletecon.json
Normal file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{ "type": "over", "time": 1439215250633, "x": 0, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250634, "x": 0, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250650, "x": 1, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250666, "x": 3, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250683, "x": 7, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250700, "x": 13, "y": 118, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250737, "x": 28, "y": 121, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250794, "x": 36, "y": 123, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250804, "x": 36, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250821, "x": 37, "y": 126, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250839, "x": 37, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250855, "x": 37, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250872, "x": 37, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250889, "x": 37, "y": 131, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215250914, "x": 37, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215251063, "x": 35, "y": 140, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215251066, "x": 35, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215251224, "x": 35, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215251241, "x": 34, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215251259, "x": 34, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215251276, "x": 34, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215251482, "x": 34, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215251585, "x": 34, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215252281, "x": 34, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215252385, "x": 34, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252857, "x": 33, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252874, "x": 31, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252915, "x": 28, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252925, "x": 26, "y": 148, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252943, "x": 22, "y": 148, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252960, "x": 20, "y": 149, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252978, "x": 17, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215252995, "x": 10, "y": 151, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215253012, "x": 2, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1439215253030, "x": -12, "y": 163, "evt": { "button": 0 } }
|
||||
]
|
||||
147
packages/noodl-editor/tests/recordings/movenode.json
Normal file
@@ -0,0 +1,147 @@
|
||||
[
|
||||
{ "type": "move", "time": 1401786837103, "x": 1, "y": 138, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837119, "x": 9, "y": 133, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837136, "x": 17, "y": 127, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837153, "x": 26, "y": 123, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837170, "x": 32, "y": 121, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837187, "x": 37, "y": 120, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837204, "x": 41, "y": 119, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837221, "x": 44, "y": 119, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837238, "x": 47, "y": 118, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837255, "x": 51, "y": 118, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837272, "x": 54, "y": 116, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837288, "x": 57, "y": 116, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837305, "x": 60, "y": 115, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837356, "x": 66, "y": 115, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837358, "x": 69, "y": 114, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837375, "x": 72, "y": 113, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837393, "x": 74, "y": 112, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837410, "x": 78, "y": 109, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837426, "x": 80, "y": 107, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837443, "x": 83, "y": 103, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837460, "x": 85, "y": 101, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837478, "x": 87, "y": 100, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837495, "x": 88, "y": 99, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837513, "x": 89, "y": 98, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837530, "x": 90, "y": 97, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837546, "x": 91, "y": 96, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837563, "x": 93, "y": 95, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837581, "x": 94, "y": 94, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837599, "x": 96, "y": 93, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837616, "x": 97, "y": 93, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837632, "x": 98, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837649, "x": 99, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837667, "x": 100, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837690, "x": 101, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837721, "x": 101, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837738, "x": 101, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837755, "x": 102, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837771, "x": 104, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837788, "x": 105, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837806, "x": 106, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837824, "x": 107, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837841, "x": 108, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837857, "x": 108, "y": 90, "evt": {} },
|
||||
{ "type": "move", "time": 1401786837875, "x": 109, "y": 90, "evt": {} },
|
||||
{ "type": "move", "time": 1401786838991, "x": 109, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839008, "x": 110, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839029, "x": 112, "y": 91, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839043, "x": 112, "y": 92, "evt": {} },
|
||||
{ "type": "down", "time": 1401786839048, "x": 112, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839435, "x": 113, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839452, "x": 117, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839469, "x": 122, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839488, "x": 128, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839505, "x": 137, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839523, "x": 144, "y": 92, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839539, "x": 154, "y": 95, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839557, "x": 166, "y": 100, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839584, "x": 175, "y": 105, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839589, "x": 187, "y": 112, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839607, "x": 202, "y": 121, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839623, "x": 210, "y": 127, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839641, "x": 221, "y": 136, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839658, "x": 232, "y": 147, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839675, "x": 238, "y": 155, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839693, "x": 246, "y": 165, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839709, "x": 252, "y": 174, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839727, "x": 256, "y": 185, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839743, "x": 257, "y": 187, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839956, "x": 257, "y": 191, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839974, "x": 257, "y": 200, "evt": {} },
|
||||
{ "type": "move", "time": 1401786839990, "x": 257, "y": 212, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840007, "x": 257, "y": 235, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840024, "x": 257, "y": 264, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840041, "x": 260, "y": 283, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840058, "x": 262, "y": 306, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840075, "x": 263, "y": 324, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840092, "x": 265, "y": 340, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840109, "x": 265, "y": 353, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840126, "x": 265, "y": 366, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840144, "x": 264, "y": 373, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840161, "x": 259, "y": 378, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840331, "x": 259, "y": 379, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840348, "x": 257, "y": 385, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840365, "x": 254, "y": 389, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840382, "x": 250, "y": 392, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840400, "x": 246, "y": 395, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840417, "x": 240, "y": 398, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840434, "x": 233, "y": 402, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840451, "x": 227, "y": 404, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840468, "x": 222, "y": 407, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840485, "x": 215, "y": 409, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840502, "x": 210, "y": 410, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840519, "x": 205, "y": 412, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840536, "x": 202, "y": 413, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840553, "x": 196, "y": 415, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840571, "x": 191, "y": 417, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840587, "x": 185, "y": 419, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840604, "x": 179, "y": 420, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840621, "x": 173, "y": 421, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840639, "x": 169, "y": 423, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840656, "x": 164, "y": 424, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840673, "x": 160, "y": 425, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840690, "x": 154, "y": 426, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840707, "x": 150, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840726, "x": 147, "y": 428, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840743, "x": 144, "y": 429, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840760, "x": 140, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840777, "x": 138, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840794, "x": 134, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840812, "x": 131, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840828, "x": 129, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840846, "x": 127, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840863, "x": 125, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840880, "x": 124, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840898, "x": 123, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786840915, "x": 122, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841315, "x": 121, "y": 430, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841332, "x": 120, "y": 429, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841350, "x": 119, "y": 428, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841366, "x": 118, "y": 428, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841384, "x": 118, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841408, "x": 117, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841418, "x": 116, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841436, "x": 115, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841453, "x": 114, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841504, "x": 113, "y": 427, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841509, "x": 112, "y": 426, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841533, "x": 111, "y": 426, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841653, "x": 110, "y": 426, "evt": {} },
|
||||
{ "type": "move", "time": 1401786841670, "x": 110, "y": 425, "evt": {} },
|
||||
{ "type": "up", "time": 1401786842595, "x": 110, "y": 425, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844368, "x": 110, "y": 424, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844385, "x": 111, "y": 419, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844402, "x": 121, "y": 410, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844419, "x": 145, "y": 392, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844437, "x": 175, "y": 375, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844453, "x": 214, "y": 359, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844470, "x": 261, "y": 343, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844487, "x": 309, "y": 328, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844509, "x": 332, "y": 322, "evt": {} },
|
||||
{ "type": "move", "time": 1401786844522, "x": 353, "y": 317, "evt": {} },
|
||||
{ "type": "move", "time": 1401786845065, "x": 353, "y": 316, "evt": {} },
|
||||
{ "type": "move", "time": 1401786845082, "x": 360, "y": 311, "evt": {} },
|
||||
{ "type": "move", "time": 1401786845099, "x": 371, "y": 300, "evt": {} },
|
||||
{ "type": "move", "time": 1401786845116, "x": 399, "y": 282, "evt": {} }
|
||||
]
|
||||
158
packages/noodl-editor/tests/recordings/multimove.json
Normal file
@@ -0,0 +1,158 @@
|
||||
[
|
||||
{ "type": "move", "time": 1401787196416, "x": 1, "y": 75, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196433, "x": 5, "y": 76, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196450, "x": 8, "y": 79, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196466, "x": 12, "y": 82, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196484, "x": 15, "y": 84, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196501, "x": 19, "y": 84, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196518, "x": 22, "y": 85, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196535, "x": 23, "y": 86, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196553, "x": 24, "y": 86, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196570, "x": 25, "y": 86, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196595, "x": 26, "y": 86, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196618, "x": 27, "y": 86, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196636, "x": 27, "y": 87, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196653, "x": 28, "y": 87, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1401787196834, "x": 28, "y": 87, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787196996, "x": 29, "y": 87, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197013, "x": 32, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197030, "x": 36, "y": 90, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197047, "x": 46, "y": 98, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197064, "x": 66, "y": 113, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197095, "x": 81, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197098, "x": 102, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197116, "x": 120, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197133, "x": 133, "y": 152, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197150, "x": 145, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197167, "x": 151, "y": 159, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197184, "x": 158, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197201, "x": 162, "y": 164, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197219, "x": 165, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197236, "x": 168, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197252, "x": 171, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197269, "x": 173, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197286, "x": 176, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197304, "x": 179, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197320, "x": 182, "y": 170, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197338, "x": 185, "y": 171, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197356, "x": 189, "y": 172, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197372, "x": 191, "y": 174, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197389, "x": 193, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197406, "x": 195, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197423, "x": 196, "y": 177, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197441, "x": 198, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197458, "x": 199, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197475, "x": 200, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197492, "x": 201, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197508, "x": 202, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197525, "x": 203, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197543, "x": 204, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197560, "x": 205, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197577, "x": 206, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1401787197642, "x": 206, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197790, "x": 183, "y": 177, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197807, "x": 175, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197824, "x": 167, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197841, "x": 161, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197858, "x": 153, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197875, "x": 145, "y": 154, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197893, "x": 138, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197909, "x": 132, "y": 139, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197927, "x": 128, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197943, "x": 125, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197960, "x": 123, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197977, "x": 121, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787197995, "x": 119, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198012, "x": 118, "y": 116, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198030, "x": 117, "y": 113, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198049, "x": 116, "y": 111, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198066, "x": 115, "y": 108, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198082, "x": 114, "y": 104, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198099, "x": 113, "y": 103, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198119, "x": 112, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198134, "x": 112, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198150, "x": 111, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198174, "x": 111, "y": 101, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198200, "x": 111, "y": 100, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198217, "x": 109, "y": 99, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198234, "x": 109, "y": 98, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198250, "x": 109, "y": 97, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198290, "x": 109, "y": 96, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198370, "x": 109, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198387, "x": 109, "y": 94, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198404, "x": 109, "y": 93, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1401787198435, "x": 109, "y": 93, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198586, "x": 108, "y": 93, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198603, "x": 112, "y": 93, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198620, "x": 120, "y": 93, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198637, "x": 135, "y": 93, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198654, "x": 157, "y": 101, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198672, "x": 188, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198692, "x": 218, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198706, "x": 244, "y": 169, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198723, "x": 262, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198740, "x": 285, "y": 238, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198757, "x": 294, "y": 263, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198773, "x": 302, "y": 293, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198791, "x": 307, "y": 309, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198824, "x": 308, "y": 321, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198978, "x": 308, "y": 322, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787198995, "x": 301, "y": 329, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199012, "x": 294, "y": 338, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199029, "x": 287, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199046, "x": 279, "y": 352, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199063, "x": 269, "y": 362, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199081, "x": 258, "y": 367, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199098, "x": 248, "y": 371, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199114, "x": 238, "y": 375, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199131, "x": 228, "y": 377, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199148, "x": 218, "y": 379, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199165, "x": 209, "y": 381, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199183, "x": 200, "y": 383, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199200, "x": 195, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199220, "x": 190, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199237, "x": 185, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199253, "x": 180, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199271, "x": 175, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199289, "x": 170, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199304, "x": 166, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199322, "x": 162, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199339, "x": 159, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199355, "x": 156, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199373, "x": 153, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199390, "x": 150, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199407, "x": 147, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199425, "x": 143, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199442, "x": 139, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199459, "x": 137, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199475, "x": 134, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199510, "x": 131, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199515, "x": 130, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199527, "x": 128, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199545, "x": 127, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199562, "x": 126, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199580, "x": 124, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199596, "x": 123, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199613, "x": 122, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199630, "x": 121, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199648, "x": 120, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199665, "x": 119, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199724, "x": 118, "y": 390, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199740, "x": 118, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199758, "x": 117, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199788, "x": 116, "y": 389, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199805, "x": 116, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199821, "x": 115, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199844, "x": 115, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199860, "x": 114, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199877, "x": 114, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199895, "x": 113, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199912, "x": 112, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199930, "x": 111, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199949, "x": 111, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199973, "x": 110, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787199989, "x": 110, "y": 383, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1401787200242, "x": 110, "y": 383, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787200554, "x": 46, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1401787200571, "x": 20, "y": 392, "evt": { "button": 0 } }
|
||||
]
|
||||
342
packages/noodl-editor/tests/recordings/multirearrange.json
Normal file
@@ -0,0 +1,342 @@
|
||||
[
|
||||
{ "type": "over", "time": 1439215637976, "x": 0, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215637977, "x": 0, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215637992, "x": 2, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638087, "x": 4, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638104, "x": 5, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638116, "x": 8, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638132, "x": 13, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638150, "x": 20, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638166, "x": 26, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638187, "x": 27, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215638371, "x": 27, "y": 88, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638434, "x": 27, "y": 89, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638451, "x": 28, "y": 89, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638468, "x": 31, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638526, "x": 60, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638535, "x": 72, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638552, "x": 91, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638570, "x": 103, "y": 171, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638587, "x": 119, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638604, "x": 134, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638621, "x": 145, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638638, "x": 156, "y": 213, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638655, "x": 164, "y": 220, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638672, "x": 171, "y": 226, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638690, "x": 176, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638706, "x": 181, "y": 236, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638726, "x": 185, "y": 241, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638742, "x": 187, "y": 242, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638762, "x": 190, "y": 244, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638776, "x": 193, "y": 247, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638793, "x": 194, "y": 248, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638810, "x": 196, "y": 250, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638827, "x": 198, "y": 252, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638844, "x": 201, "y": 254, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638861, "x": 204, "y": 257, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638877, "x": 207, "y": 259, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638894, "x": 211, "y": 263, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638910, "x": 216, "y": 266, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638927, "x": 221, "y": 271, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638945, "x": 226, "y": 274, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638962, "x": 230, "y": 279, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638979, "x": 235, "y": 284, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215638996, "x": 239, "y": 287, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639013, "x": 242, "y": 290, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639030, "x": 245, "y": 293, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639048, "x": 248, "y": 295, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639065, "x": 250, "y": 297, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639082, "x": 251, "y": 298, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215639323, "x": 251, "y": 298, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639370, "x": 251, "y": 297, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639388, "x": 249, "y": 291, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639404, "x": 238, "y": 275, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639421, "x": 220, "y": 251, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639438, "x": 203, "y": 228, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639468, "x": 184, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639472, "x": 166, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639489, "x": 144, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639506, "x": 133, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639524, "x": 132, "y": 124, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639543, "x": 132, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639560, "x": 131, "y": 121, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639576, "x": 131, "y": 120, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639594, "x": 131, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639611, "x": 130, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639627, "x": 128, "y": 112, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639643, "x": 127, "y": 110, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639661, "x": 126, "y": 109, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639677, "x": 125, "y": 107, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639694, "x": 125, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639712, "x": 124, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639728, "x": 124, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215639802, "x": 124, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639922, "x": 125, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639939, "x": 127, "y": 107, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639956, "x": 132, "y": 112, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639972, "x": 142, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215639989, "x": 153, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640006, "x": 164, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640024, "x": 179, "y": 159, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640040, "x": 194, "y": 174, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640060, "x": 206, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640077, "x": 216, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640094, "x": 226, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640110, "x": 237, "y": 239, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640126, "x": 245, "y": 255, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640143, "x": 252, "y": 271, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640160, "x": 259, "y": 289, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640177, "x": 263, "y": 306, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640194, "x": 266, "y": 323, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640211, "x": 268, "y": 338, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640228, "x": 269, "y": 352, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640245, "x": 271, "y": 370, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640262, "x": 271, "y": 383, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640279, "x": 271, "y": 400, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640296, "x": 271, "y": 415, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640314, "x": 269, "y": 427, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640330, "x": 268, "y": 433, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640348, "x": 266, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640365, "x": 264, "y": 439, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640383, "x": 261, "y": 443, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640401, "x": 259, "y": 446, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640418, "x": 253, "y": 449, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640436, "x": 248, "y": 451, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640452, "x": 243, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640468, "x": 238, "y": 454, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640486, "x": 231, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640501, "x": 228, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640518, "x": 224, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640535, "x": 219, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640552, "x": 217, "y": 455, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640569, "x": 216, "y": 454, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640587, "x": 211, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640604, "x": 208, "y": 448, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640621, "x": 206, "y": 444, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640638, "x": 204, "y": 442, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640655, "x": 204, "y": 441, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640673, "x": 204, "y": 440, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640690, "x": 203, "y": 439, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640710, "x": 202, "y": 438, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640727, "x": 201, "y": 437, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640745, "x": 201, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640763, "x": 201, "y": 435, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640781, "x": 200, "y": 435, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215640818, "x": 200, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215641095, "x": 200, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641258, "x": 201, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641347, "x": 202, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641380, "x": 202, "y": 435, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641396, "x": 202, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641414, "x": 202, "y": 438, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641431, "x": 202, "y": 441, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641447, "x": 204, "y": 447, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641467, "x": 210, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641482, "x": 213, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641499, "x": 213, "y": 473, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641516, "x": 215, "y": 479, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641533, "x": 217, "y": 484, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641550, "x": 218, "y": 486, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641567, "x": 220, "y": 486, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641587, "x": 220, "y": 487, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641605, "x": 221, "y": 487, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641621, "x": 225, "y": 487, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641639, "x": 236, "y": 488, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641656, "x": 256, "y": 488, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641676, "x": 278, "y": 486, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641693, "x": 296, "y": 483, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641709, "x": 312, "y": 480, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641727, "x": 318, "y": 477, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641765, "x": 322, "y": 474, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641802, "x": 321, "y": 474, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641820, "x": 317, "y": 473, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641837, "x": 313, "y": 469, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641854, "x": 308, "y": 467, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641871, "x": 303, "y": 467, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641888, "x": 300, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641906, "x": 296, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215641924, "x": 295, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215642074, "x": 295, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215642210, "x": 295, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642258, "x": 294, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642278, "x": 293, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642306, "x": 290, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642309, "x": 286, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642326, "x": 278, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642343, "x": 269, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642359, "x": 261, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642377, "x": 254, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642394, "x": 252, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642411, "x": 251, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642474, "x": 252, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642492, "x": 253, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642510, "x": 256, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642526, "x": 264, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642543, "x": 270, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642561, "x": 278, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642578, "x": 283, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642594, "x": 285, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642611, "x": 286, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642659, "x": 287, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215642682, "x": 287, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642722, "x": 286, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642740, "x": 281, "y": 466, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642756, "x": 267, "y": 465, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642775, "x": 244, "y": 463, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642794, "x": 217, "y": 460, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642812, "x": 192, "y": 460, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642826, "x": 176, "y": 460, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642844, "x": 160, "y": 461, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642861, "x": 148, "y": 461, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642878, "x": 137, "y": 461, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642894, "x": 128, "y": 459, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642912, "x": 119, "y": 458, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642928, "x": 110, "y": 458, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642945, "x": 103, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642962, "x": 97, "y": 455, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642980, "x": 87, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215642997, "x": 82, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643014, "x": 77, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643031, "x": 72, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643049, "x": 69, "y": 450, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643066, "x": 66, "y": 449, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643083, "x": 63, "y": 448, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643101, "x": 58, "y": 446, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643118, "x": 53, "y": 445, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643135, "x": 52, "y": 444, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643152, "x": 51, "y": 444, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215643196, "x": 51, "y": 444, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643260, "x": 52, "y": 444, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643279, "x": 53, "y": 444, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643294, "x": 59, "y": 446, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643309, "x": 69, "y": 448, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643350, "x": 98, "y": 453, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643360, "x": 108, "y": 455, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643378, "x": 118, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643395, "x": 124, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643412, "x": 127, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643498, "x": 128, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643515, "x": 129, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643562, "x": 129, "y": 457, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643587, "x": 129, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215643637, "x": 129, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643660, "x": 130, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643678, "x": 131, "y": 456, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643694, "x": 134, "y": 455, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643711, "x": 139, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643729, "x": 145, "y": 449, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643744, "x": 152, "y": 446, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643761, "x": 161, "y": 442, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643778, "x": 167, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643795, "x": 174, "y": 432, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643811, "x": 180, "y": 425, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643828, "x": 185, "y": 420, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643845, "x": 190, "y": 414, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643862, "x": 194, "y": 407, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643880, "x": 198, "y": 397, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643897, "x": 203, "y": 387, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643914, "x": 203, "y": 378, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643932, "x": 204, "y": 371, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643949, "x": 204, "y": 366, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643965, "x": 204, "y": 361, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215643983, "x": 204, "y": 357, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644002, "x": 204, "y": 352, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644019, "x": 204, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644036, "x": 204, "y": 336, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644051, "x": 204, "y": 321, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644070, "x": 202, "y": 308, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644085, "x": 201, "y": 291, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644103, "x": 199, "y": 273, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644119, "x": 196, "y": 257, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644137, "x": 191, "y": 243, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644153, "x": 190, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644169, "x": 186, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644187, "x": 181, "y": 214, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644203, "x": 178, "y": 209, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644220, "x": 176, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644237, "x": 173, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644254, "x": 172, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644272, "x": 171, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644290, "x": 170, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644306, "x": 169, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215644499, "x": 169, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644602, "x": 169, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644620, "x": 169, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644636, "x": 169, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644652, "x": 169, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644669, "x": 174, "y": 250, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644687, "x": 180, "y": 277, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644704, "x": 187, "y": 313, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644721, "x": 194, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644738, "x": 197, "y": 377, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644755, "x": 197, "y": 409, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644772, "x": 197, "y": 432, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644789, "x": 197, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644806, "x": 197, "y": 463, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644823, "x": 197, "y": 469, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644843, "x": 197, "y": 473, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644859, "x": 197, "y": 476, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644877, "x": 196, "y": 480, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644893, "x": 190, "y": 484, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644910, "x": 184, "y": 490, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644927, "x": 179, "y": 494, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644944, "x": 175, "y": 498, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644963, "x": 173, "y": 500, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644977, "x": 172, "y": 502, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215644994, "x": 170, "y": 504, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645011, "x": 169, "y": 505, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645035, "x": 168, "y": 505, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645067, "x": 168, "y": 506, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645095, "x": 168, "y": 507, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645115, "x": 168, "y": 508, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645170, "x": 168, "y": 509, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645212, "x": 168, "y": 510, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645227, "x": 168, "y": 511, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215645282, "x": 168, "y": 511, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645354, "x": 167, "y": 511, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645387, "x": 169, "y": 511, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645403, "x": 172, "y": 511, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645420, "x": 181, "y": 510, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645437, "x": 188, "y": 509, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645454, "x": 199, "y": 504, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645471, "x": 209, "y": 497, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645489, "x": 219, "y": 490, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645506, "x": 231, "y": 477, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645524, "x": 241, "y": 463, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645541, "x": 246, "y": 450, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645561, "x": 252, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645577, "x": 260, "y": 413, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645594, "x": 264, "y": 395, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645611, "x": 266, "y": 374, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645628, "x": 270, "y": 353, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645644, "x": 271, "y": 333, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645661, "x": 274, "y": 318, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645677, "x": 274, "y": 303, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645694, "x": 275, "y": 287, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645713, "x": 275, "y": 271, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645728, "x": 272, "y": 260, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645745, "x": 272, "y": 247, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645762, "x": 269, "y": 238, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645780, "x": 267, "y": 230, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645796, "x": 266, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645814, "x": 265, "y": 217, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645831, "x": 264, "y": 213, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645848, "x": 264, "y": 210, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645865, "x": 263, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645882, "x": 263, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645900, "x": 262, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645918, "x": 261, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215645935, "x": 261, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215646074, "x": 261, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646258, "x": 260, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646279, "x": 258, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646295, "x": 254, "y": 213, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646311, "x": 247, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646327, "x": 232, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646345, "x": 212, "y": 243, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646361, "x": 187, "y": 259, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646378, "x": 147, "y": 276, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646395, "x": 80, "y": 293, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215646412, "x": 9, "y": 305, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1439215646429, "x": -70, "y": 309, "evt": { "button": 0 } }
|
||||
]
|
||||
167
packages/noodl-editor/tests/recordings/pan.json
Normal file
@@ -0,0 +1,167 @@
|
||||
[
|
||||
{ "type": "over", "time": 1431673500632, "x": 3, "y": 472, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500633, "x": 3, "y": 472, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500649, "x": 28, "y": 472, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500665, "x": 61, "y": 472, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500683, "x": 97, "y": 472, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500701, "x": 130, "y": 474, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500718, "x": 152, "y": 472, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500734, "x": 164, "y": 463, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500751, "x": 172, "y": 452, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500769, "x": 179, "y": 441, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500787, "x": 185, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500804, "x": 188, "y": 427, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500821, "x": 191, "y": 414, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500838, "x": 193, "y": 397, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500855, "x": 196, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500872, "x": 200, "y": 380, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500889, "x": 205, "y": 376, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500907, "x": 210, "y": 369, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500922, "x": 214, "y": 362, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500938, "x": 216, "y": 357, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500955, "x": 218, "y": 352, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500973, "x": 219, "y": 349, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673500991, "x": 220, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501006, "x": 220, "y": 340, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501024, "x": 221, "y": 334, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501041, "x": 221, "y": 329, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501058, "x": 221, "y": 325, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501076, "x": 221, "y": 323, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501093, "x": 221, "y": 322, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501110, "x": 222, "y": 321, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673501127, "x": 222, "y": 319, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1431673501148, "x": 222, "y": 319, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501164, "x": 222, "y": 319, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501219, "x": 222, "y": 320, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501240, "x": 222, "y": 322, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501258, "x": 222, "y": 326, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501270, "x": 222, "y": 333, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501322, "x": 226, "y": 364, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501347, "x": 228, "y": 373, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501356, "x": 229, "y": 383, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501373, "x": 231, "y": 394, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501389, "x": 231, "y": 403, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501407, "x": 232, "y": 408, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501424, "x": 232, "y": 414, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501441, "x": 233, "y": 419, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501458, "x": 233, "y": 424, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501475, "x": 234, "y": 427, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501493, "x": 234, "y": 429, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501510, "x": 234, "y": 430, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501605, "x": 234, "y": 429, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501623, "x": 234, "y": 420, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501639, "x": 234, "y": 405, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501654, "x": 235, "y": 388, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501673, "x": 237, "y": 372, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501690, "x": 237, "y": 356, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501710, "x": 241, "y": 336, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501724, "x": 241, "y": 316, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501739, "x": 243, "y": 290, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501757, "x": 243, "y": 271, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501774, "x": 244, "y": 257, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501790, "x": 244, "y": 248, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501807, "x": 244, "y": 242, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501824, "x": 244, "y": 240, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501891, "x": 244, "y": 241, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501909, "x": 244, "y": 245, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501926, "x": 244, "y": 255, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501943, "x": 244, "y": 267, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501960, "x": 244, "y": 283, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501977, "x": 244, "y": 300, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673501994, "x": 246, "y": 315, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502011, "x": 248, "y": 328, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502028, "x": 248, "y": 337, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502045, "x": 248, "y": 344, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502062, "x": 248, "y": 349, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502078, "x": 248, "y": 351, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502096, "x": 248, "y": 352, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502179, "x": 248, "y": 351, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502197, "x": 247, "y": 347, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502214, "x": 246, "y": 340, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502231, "x": 246, "y": 332, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502248, "x": 246, "y": 326, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502265, "x": 246, "y": 320, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502282, "x": 246, "y": 316, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502299, "x": 246, "y": 311, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502317, "x": 246, "y": 310, "evt": { "button": 2 } },
|
||||
{ "type": "up", "time": 1431673502475, "x": 246, "y": 310, "evt": { "button": 2 } },
|
||||
{ "type": "move", "time": 1431673502516, "x": 245, "y": 310, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502589, "x": 245, "y": 311, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502605, "x": 245, "y": 314, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502622, "x": 246, "y": 320, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502639, "x": 248, "y": 330, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502656, "x": 253, "y": 338, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502674, "x": 257, "y": 349, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502691, "x": 261, "y": 357, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673502708, "x": 263, "y": 366, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502725, "x": 266, "y": 375, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502741, "x": 266, "y": 382, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502759, "x": 266, "y": 387, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502776, "x": 264, "y": 392, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502793, "x": 264, "y": 394, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502817, "x": 264, "y": 395, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502829, "x": 263, "y": 396, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502899, "x": 262, "y": 396, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502924, "x": 262, "y": 395, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502941, "x": 261, "y": 394, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502958, "x": 261, "y": 393, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502981, "x": 261, "y": 392, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "down", "time": 1431673502989, "x": 261, "y": 392, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673502998, "x": 261, "y": 391, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503014, "x": 261, "y": 389, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503031, "x": 261, "y": 386, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503048, "x": 261, "y": 380, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503065, "x": 261, "y": 375, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503081, "x": 261, "y": 366, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503098, "x": 261, "y": 355, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503115, "x": 261, "y": 344, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503132, "x": 261, "y": 337, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503149, "x": 260, "y": 334, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503174, "x": 260, "y": 333, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503219, "x": 260, "y": 333, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503239, "x": 260, "y": 334, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503256, "x": 260, "y": 342, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503275, "x": 260, "y": 351, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503291, "x": 260, "y": 362, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503306, "x": 260, "y": 378, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503323, "x": 260, "y": 394, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503339, "x": 260, "y": 414, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503357, "x": 260, "y": 433, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503374, "x": 260, "y": 448, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503391, "x": 260, "y": 459, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503407, "x": 260, "y": 466, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503425, "x": 260, "y": 469, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503441, "x": 260, "y": 472, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503531, "x": 260, "y": 470, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503548, "x": 261, "y": 455, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503565, "x": 261, "y": 441, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503582, "x": 261, "y": 425, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503600, "x": 261, "y": 410, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503616, "x": 261, "y": 397, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503634, "x": 261, "y": 387, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503650, "x": 261, "y": 379, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503667, "x": 261, "y": 372, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503685, "x": 261, "y": 367, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503702, "x": 261, "y": 366, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503719, "x": 261, "y": 365, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503779, "x": 261, "y": 366, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503797, "x": 262, "y": 371, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503814, "x": 262, "y": 380, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503831, "x": 262, "y": 388, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503848, "x": 262, "y": 397, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503865, "x": 262, "y": 409, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503883, "x": 262, "y": 417, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503900, "x": 262, "y": 423, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503917, "x": 262, "y": 428, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503934, "x": 262, "y": 432, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503950, "x": 263, "y": 434, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673503973, "x": 263, "y": 435, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "up", "time": 1431673504179, "x": 263, "y": 435, "evt": { "button": 0, "spaceKey": true } },
|
||||
{ "type": "move", "time": 1431673504307, "x": 261, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673504325, "x": 251, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673504342, "x": 235, "y": 436, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673504359, "x": 198, "y": 437, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673504376, "x": 147, "y": 434, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1431673504393, "x": 75, "y": 430, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1431673504411, "x": -12, "y": 421, "evt": { "button": 0 } }
|
||||
]
|
||||
182
packages/noodl-editor/tests/recordings/singlerearrange.json
Normal file
@@ -0,0 +1,182 @@
|
||||
[
|
||||
{ "type": "over", "time": 1439215782915, "x": 114, "y": 184, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215782916, "x": 114, "y": 184, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215782926, "x": 118, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215782943, "x": 120, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783049, "x": 121, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215783320, "x": 121, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783384, "x": 121, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783401, "x": 121, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783418, "x": 122, "y": 183, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783485, "x": 125, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783485, "x": 127, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783503, "x": 129, "y": 158, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783520, "x": 131, "y": 154, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783537, "x": 132, "y": 149, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783554, "x": 135, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783572, "x": 137, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783589, "x": 139, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783607, "x": 141, "y": 140, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783623, "x": 143, "y": 138, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783641, "x": 145, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783658, "x": 147, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783675, "x": 148, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783692, "x": 150, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783713, "x": 151, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783730, "x": 151, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783764, "x": 151, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783808, "x": 152, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215783824, "x": 152, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215783993, "x": 152, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784080, "x": 152, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784099, "x": 152, "y": 133, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784114, "x": 152, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784131, "x": 150, "y": 159, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784148, "x": 146, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784166, "x": 144, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784183, "x": 144, "y": 213, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784208, "x": 144, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784217, "x": 144, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784234, "x": 144, "y": 239, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784252, "x": 143, "y": 247, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784268, "x": 143, "y": 252, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784286, "x": 140, "y": 256, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784303, "x": 139, "y": 259, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784321, "x": 139, "y": 262, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784338, "x": 138, "y": 264, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784355, "x": 137, "y": 266, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784373, "x": 137, "y": 267, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784390, "x": 137, "y": 269, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784417, "x": 137, "y": 270, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784434, "x": 137, "y": 271, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784451, "x": 137, "y": 274, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784469, "x": 136, "y": 276, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784485, "x": 135, "y": 278, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784503, "x": 135, "y": 281, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784519, "x": 134, "y": 283, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784537, "x": 134, "y": 285, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784554, "x": 134, "y": 286, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784580, "x": 134, "y": 287, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784609, "x": 134, "y": 288, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784656, "x": 133, "y": 288, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784673, "x": 133, "y": 289, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215784704, "x": 133, "y": 289, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784784, "x": 133, "y": 288, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784800, "x": 133, "y": 287, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784817, "x": 134, "y": 283, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784852, "x": 147, "y": 261, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784868, "x": 158, "y": 248, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784889, "x": 165, "y": 235, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784917, "x": 172, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784919, "x": 180, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784937, "x": 184, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784953, "x": 184, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784970, "x": 185, "y": 177, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215784987, "x": 185, "y": 171, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785004, "x": 185, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785022, "x": 185, "y": 164, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785038, "x": 185, "y": 160, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785056, "x": 185, "y": 158, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785073, "x": 185, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785089, "x": 185, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785107, "x": 185, "y": 154, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785124, "x": 185, "y": 153, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785141, "x": 185, "y": 151, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785159, "x": 184, "y": 148, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785176, "x": 184, "y": 145, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785193, "x": 184, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785210, "x": 184, "y": 139, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785229, "x": 184, "y": 137, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785247, "x": 184, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785263, "x": 183, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785280, "x": 183, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785299, "x": 183, "y": 131, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785314, "x": 183, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785337, "x": 183, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785361, "x": 182, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215785672, "x": 182, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785856, "x": 182, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785874, "x": 182, "y": 131, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785890, "x": 182, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785908, "x": 182, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785925, "x": 182, "y": 138, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785942, "x": 182, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785959, "x": 182, "y": 149, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785977, "x": 182, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215785994, "x": 182, "y": 159, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786010, "x": 182, "y": 161, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786030, "x": 182, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786047, "x": 182, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786063, "x": 182, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786081, "x": 182, "y": 170, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786100, "x": 180, "y": 177, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786114, "x": 177, "y": 184, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786132, "x": 174, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786148, "x": 172, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786165, "x": 170, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786182, "x": 168, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786199, "x": 165, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786216, "x": 163, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786234, "x": 159, "y": 210, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786251, "x": 153, "y": 213, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786268, "x": 150, "y": 217, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786284, "x": 148, "y": 219, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786301, "x": 145, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786325, "x": 143, "y": 225, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786336, "x": 141, "y": 227, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786407, "x": 141, "y": 228, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786425, "x": 141, "y": 229, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786442, "x": 140, "y": 230, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786459, "x": 140, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786476, "x": 140, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786494, "x": 140, "y": 233, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786543, "x": 140, "y": 234, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439215786735, "x": 140, "y": 234, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786816, "x": 140, "y": 233, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786833, "x": 140, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786850, "x": 140, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786867, "x": 140, "y": 229, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786884, "x": 140, "y": 226, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786901, "x": 140, "y": 223, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786918, "x": 140, "y": 220, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786935, "x": 140, "y": 216, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786953, "x": 140, "y": 212, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786970, "x": 143, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215786987, "x": 143, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787003, "x": 144, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787020, "x": 145, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787037, "x": 146, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787055, "x": 147, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787071, "x": 148, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787088, "x": 148, "y": 183, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787104, "x": 150, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787122, "x": 151, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787139, "x": 151, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787156, "x": 151, "y": 172, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787172, "x": 151, "y": 170, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787190, "x": 151, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787207, "x": 151, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787224, "x": 151, "y": 164, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787241, "x": 151, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787258, "x": 151, "y": 160, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787275, "x": 151, "y": 158, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787301, "x": 151, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787314, "x": 151, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787332, "x": 150, "y": 154, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787348, "x": 150, "y": 153, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787366, "x": 150, "y": 152, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787393, "x": 150, "y": 151, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787464, "x": 150, "y": 151, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787508, "x": 150, "y": 149, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787515, "x": 150, "y": 148, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215787671, "x": 150, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439215788056, "x": 150, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788272, "x": 150, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788289, "x": 150, "y": 148, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788305, "x": 149, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788322, "x": 145, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788339, "x": 136, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788356, "x": 113, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439215788401, "x": 31, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1439215788409, "x": -14, "y": 210, "evt": { "button": 0 } }
|
||||
]
|
||||
155
packages/noodl-editor/tests/recordings/undoarrange.json
Normal file
@@ -0,0 +1,155 @@
|
||||
[
|
||||
{ "type": "over", "time": 1439216575369, "x": 14, "y": 413, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575370, "x": 14, "y": 413, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575386, "x": 65, "y": 424, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575403, "x": 103, "y": 433, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575420, "x": 138, "y": 442, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575437, "x": 170, "y": 447, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575455, "x": 195, "y": 447, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575472, "x": 216, "y": 448, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575489, "x": 233, "y": 448, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575510, "x": 246, "y": 446, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575528, "x": 254, "y": 442, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575542, "x": 262, "y": 440, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575559, "x": 268, "y": 435, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575576, "x": 273, "y": 432, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575594, "x": 276, "y": 429, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575610, "x": 278, "y": 424, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575626, "x": 279, "y": 414, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575643, "x": 279, "y": 402, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575661, "x": 277, "y": 388, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575676, "x": 270, "y": 374, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575694, "x": 263, "y": 361, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575710, "x": 256, "y": 352, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575742, "x": 251, "y": 345, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575744, "x": 251, "y": 342, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216575762, "x": 250, "y": 341, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439216575915, "x": 250, "y": 341, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576055, "x": 209, "y": 293, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576057, "x": 190, "y": 279, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576074, "x": 177, "y": 266, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576092, "x": 168, "y": 258, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576108, "x": 160, "y": 250, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576125, "x": 156, "y": 243, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576142, "x": 152, "y": 237, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576159, "x": 148, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576175, "x": 142, "y": 227, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576192, "x": 138, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576212, "x": 135, "y": 216, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576227, "x": 132, "y": 212, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576244, "x": 128, "y": 209, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576261, "x": 125, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576278, "x": 124, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576295, "x": 123, "y": 205, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576313, "x": 122, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576330, "x": 122, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576347, "x": 121, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576364, "x": 119, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576381, "x": 118, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576398, "x": 117, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576416, "x": 115, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576434, "x": 113, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576449, "x": 111, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576467, "x": 110, "y": 190, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576483, "x": 110, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439216576651, "x": 110, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576842, "x": 111, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576861, "x": 112, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576883, "x": 113, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576922, "x": 114, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576939, "x": 115, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576959, "x": 116, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216576988, "x": 120, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577004, "x": 125, "y": 190, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577011, "x": 131, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577026, "x": 134, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577043, "x": 137, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439216577243, "x": 137, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577315, "x": 138, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577339, "x": 139, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577356, "x": 141, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577373, "x": 146, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577394, "x": 150, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577411, "x": 155, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577426, "x": 160, "y": 172, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577456, "x": 162, "y": 169, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577460, "x": 168, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577475, "x": 170, "y": 161, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577493, "x": 172, "y": 158, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577510, "x": 173, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577527, "x": 175, "y": 153, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577543, "x": 177, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577562, "x": 179, "y": 148, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577578, "x": 179, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577596, "x": 180, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577613, "x": 181, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577630, "x": 182, "y": 139, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577647, "x": 182, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577664, "x": 183, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577683, "x": 183, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577700, "x": 183, "y": 131, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577718, "x": 183, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577734, "x": 183, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577751, "x": 183, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216577768, "x": 183, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439216578034, "x": 183, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578227, "x": 183, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578244, "x": 183, "y": 140, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578260, "x": 181, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578277, "x": 179, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578294, "x": 179, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578311, "x": 177, "y": 228, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578328, "x": 177, "y": 257, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578355, "x": 177, "y": 286, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578362, "x": 174, "y": 309, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578379, "x": 170, "y": 325, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578395, "x": 170, "y": 329, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578412, "x": 170, "y": 332, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578430, "x": 170, "y": 334, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578466, "x": 170, "y": 335, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439216578562, "x": 170, "y": 335, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439216578722, "x": 170, "y": 335, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578858, "x": 170, "y": 334, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578876, "x": 170, "y": 329, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578893, "x": 169, "y": 323, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578910, "x": 167, "y": 310, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578928, "x": 161, "y": 292, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578943, "x": 155, "y": 275, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578959, "x": 148, "y": 261, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578977, "x": 141, "y": 249, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216578994, "x": 139, "y": 243, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579012, "x": 138, "y": 240, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579028, "x": 137, "y": 237, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579045, "x": 137, "y": 234, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579063, "x": 137, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579080, "x": 136, "y": 229, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579098, "x": 135, "y": 226, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579114, "x": 134, "y": 222, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579132, "x": 133, "y": 220, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579150, "x": 132, "y": 220, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1439216579418, "x": 132, "y": 220, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579522, "x": 132, "y": 221, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579540, "x": 133, "y": 226, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579557, "x": 135, "y": 231, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579575, "x": 139, "y": 238, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579593, "x": 142, "y": 244, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579610, "x": 144, "y": 249, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579628, "x": 145, "y": 255, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579644, "x": 148, "y": 261, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579659, "x": 151, "y": 264, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579676, "x": 154, "y": 267, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579695, "x": 155, "y": 269, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579710, "x": 156, "y": 272, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579728, "x": 157, "y": 274, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579745, "x": 158, "y": 277, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579761, "x": 161, "y": 280, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579779, "x": 162, "y": 280, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216579797, "x": 162, "y": 281, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1439216579938, "x": 162, "y": 281, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216580104, "x": 157, "y": 291, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216580117, "x": 140, "y": 309, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216580134, "x": 107, "y": 340, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216580151, "x": 65, "y": 373, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1439216580169, "x": 15, "y": 402, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1439216580186, "x": -34, "y": 422, "evt": { "button": 0 } }
|
||||
]
|
||||
212
packages/noodl-editor/tests/recordings/undocutchildren.json
Normal file
@@ -0,0 +1,212 @@
|
||||
[
|
||||
{ "type": "over", "time": 1405373847970, "x": 43, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373847970, "x": 43, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373847986, "x": 94, "y": 208, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848003, "x": 125, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848020, "x": 146, "y": 206, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848037, "x": 157, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848054, "x": 160, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848072, "x": 162, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848110, "x": 162, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848112, "x": 162, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848129, "x": 162, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848146, "x": 163, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848168, "x": 163, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848192, "x": 163, "y": 197, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848240, "x": 163, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848256, "x": 163, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848273, "x": 162, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848290, "x": 162, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848308, "x": 161, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848325, "x": 160, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1405373848400, "x": 160, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848456, "x": 160, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848473, "x": 160, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848489, "x": 161, "y": 182, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848507, "x": 163, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848523, "x": 165, "y": 172, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848540, "x": 170, "y": 162, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848557, "x": 172, "y": 156, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848575, "x": 179, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848591, "x": 180, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848609, "x": 180, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848626, "x": 181, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848643, "x": 181, "y": 133, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848660, "x": 181, "y": 132, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848676, "x": 181, "y": 131, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848696, "x": 181, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848713, "x": 182, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848730, "x": 182, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848747, "x": 183, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848764, "x": 183, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848782, "x": 184, "y": 125, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848799, "x": 184, "y": 122, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848816, "x": 185, "y": 121, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848832, "x": 186, "y": 120, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373848849, "x": 186, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1405373849056, "x": 186, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849064, "x": 186, "y": 118, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849128, "x": 186, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849146, "x": 185, "y": 126, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849163, "x": 181, "y": 137, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849180, "x": 174, "y": 158, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849197, "x": 166, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849214, "x": 159, "y": 217, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849231, "x": 152, "y": 241, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849248, "x": 148, "y": 262, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849265, "x": 148, "y": 276, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849281, "x": 147, "y": 280, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849298, "x": 144, "y": 285, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849315, "x": 144, "y": 288, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849332, "x": 144, "y": 290, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849350, "x": 143, "y": 291, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849367, "x": 141, "y": 292, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849384, "x": 141, "y": 295, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849401, "x": 140, "y": 295, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849528, "x": 140, "y": 294, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849559, "x": 140, "y": 293, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1405373849568, "x": 140, "y": 293, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849616, "x": 140, "y": 292, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849632, "x": 141, "y": 290, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849649, "x": 143, "y": 286, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849666, "x": 149, "y": 279, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849683, "x": 156, "y": 268, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849700, "x": 167, "y": 254, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849717, "x": 176, "y": 239, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849734, "x": 187, "y": 224, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849752, "x": 194, "y": 212, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849769, "x": 197, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849786, "x": 198, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849803, "x": 199, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849821, "x": 201, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849837, "x": 201, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849854, "x": 201, "y": 184, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849871, "x": 203, "y": 183, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849888, "x": 203, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849905, "x": 203, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849922, "x": 203, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849944, "x": 203, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849961, "x": 204, "y": 177, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849978, "x": 204, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373849995, "x": 204, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850016, "x": 204, "y": 174, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1405373850168, "x": 204, "y": 174, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850248, "x": 204, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850265, "x": 201, "y": 182, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850281, "x": 196, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850298, "x": 188, "y": 214, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850315, "x": 174, "y": 245, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850332, "x": 159, "y": 281, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850350, "x": 146, "y": 317, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850367, "x": 136, "y": 346, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850384, "x": 130, "y": 361, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850402, "x": 129, "y": 367, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850419, "x": 129, "y": 372, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850436, "x": 128, "y": 375, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850453, "x": 127, "y": 378, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850469, "x": 125, "y": 380, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850487, "x": 124, "y": 381, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850504, "x": 124, "y": 383, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850522, "x": 123, "y": 384, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850539, "x": 122, "y": 385, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850560, "x": 122, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1405373850656, "x": 122, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850720, "x": 122, "y": 386, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850737, "x": 122, "y": 382, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850754, "x": 126, "y": 372, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850771, "x": 132, "y": 353, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850788, "x": 140, "y": 326, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850804, "x": 151, "y": 289, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850821, "x": 157, "y": 259, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850838, "x": 161, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850855, "x": 167, "y": 207, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850872, "x": 167, "y": 186, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850889, "x": 169, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850906, "x": 169, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850923, "x": 169, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850940, "x": 169, "y": 139, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850958, "x": 169, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850976, "x": 169, "y": 133, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373850992, "x": 169, "y": 130, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851009, "x": 169, "y": 128, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851026, "x": 169, "y": 123, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851043, "x": 169, "y": 118, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851059, "x": 167, "y": 113, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851077, "x": 167, "y": 107, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851093, "x": 167, "y": 103, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851111, "x": 166, "y": 99, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851128, "x": 165, "y": 97, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851145, "x": 165, "y": 96, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851168, "x": 165, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1405373851544, "x": 165, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851672, "x": 164, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851690, "x": 164, "y": 100, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851705, "x": 164, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851722, "x": 163, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851740, "x": 163, "y": 107, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851757, "x": 162, "y": 111, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851774, "x": 162, "y": 113, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851796, "x": 161, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851809, "x": 160, "y": 119, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851826, "x": 160, "y": 120, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851872, "x": 160, "y": 121, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851889, "x": 164, "y": 129, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851905, "x": 177, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851922, "x": 201, "y": 151, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851940, "x": 226, "y": 159, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851957, "x": 249, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851974, "x": 268, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373851991, "x": 283, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852008, "x": 293, "y": 167, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852025, "x": 297, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852042, "x": 299, "y": 168, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852104, "x": 299, "y": 169, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852128, "x": 299, "y": 170, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852145, "x": 299, "y": 171, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852168, "x": 299, "y": 172, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852185, "x": 298, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852201, "x": 296, "y": 175, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852219, "x": 292, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852236, "x": 288, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852253, "x": 281, "y": 183, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852270, "x": 276, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852287, "x": 272, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852305, "x": 271, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852322, "x": 270, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852384, "x": 270, "y": 190, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852401, "x": 270, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852432, "x": 270, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852449, "x": 270, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852466, "x": 270, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852484, "x": 269, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852501, "x": 269, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1405373852528, "x": 269, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852561, "x": 268, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852586, "x": 267, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852601, "x": 261, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852617, "x": 252, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852634, "x": 234, "y": 188, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852651, "x": 205, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852668, "x": 171, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852685, "x": 139, "y": 165, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852702, "x": 107, "y": 158, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852719, "x": 78, "y": 153, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852736, "x": 61, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852753, "x": 50, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852770, "x": 44, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852787, "x": 40, "y": 145, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852804, "x": 35, "y": 145, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852821, "x": 31, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852838, "x": 26, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852855, "x": 21, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852872, "x": 17, "y": 140, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852889, "x": 14, "y": 139, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852906, "x": 12, "y": 137, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852924, "x": 10, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373852942, "x": 9, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1405373853176, "x": 9, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "cut", "time": 1405373853518 },
|
||||
{ "type": "move", "time": 1405373853800, "x": 8, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1405373853817, "x": 4, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1405373853835, "x": -10, "y": 137, "evt": { "button": 0 } }
|
||||
]
|
||||
114
packages/noodl-editor/tests/recordings/undocutconnections.json
Normal file
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{ "type": "over", "time": 1412929236006, "x": 13, "y": 197, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236008, "x": 13, "y": 197, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236023, "x": 20, "y": 197, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236040, "x": 24, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236057, "x": 27, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236075, "x": 29, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236091, "x": 33, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236108, "x": 41, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236126, "x": 57, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236144, "x": 74, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236162, "x": 89, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236178, "x": 99, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236195, "x": 102, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236212, "x": 103, "y": 203, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236230, "x": 103, "y": 202, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236278, "x": 105, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236291, "x": 106, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236309, "x": 107, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236345, "x": 108, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1412929236505, "x": 108, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236561, "x": 109, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236586, "x": 111, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236603, "x": 113, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236620, "x": 119, "y": 200, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236637, "x": 126, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236654, "x": 135, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236672, "x": 145, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236689, "x": 152, "y": 201, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236707, "x": 159, "y": 199, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236725, "x": 161, "y": 198, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236750, "x": 163, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236758, "x": 165, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236776, "x": 166, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236792, "x": 167, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236809, "x": 167, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236826, "x": 167, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236844, "x": 168, "y": 181, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236860, "x": 168, "y": 178, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236878, "x": 168, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236894, "x": 168, "y": 166, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236911, "x": 166, "y": 161, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236929, "x": 165, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236947, "x": 161, "y": 150, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236964, "x": 160, "y": 147, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236980, "x": 158, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929236997, "x": 157, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237014, "x": 156, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237041, "x": 156, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1412929237153, "x": 156, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237289, "x": 160, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237307, "x": 174, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237324, "x": 192, "y": 152, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237341, "x": 217, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237358, "x": 238, "y": 164, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237376, "x": 253, "y": 169, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237393, "x": 264, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237411, "x": 268, "y": 176, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237428, "x": 271, "y": 180, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237445, "x": 273, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237462, "x": 275, "y": 187, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237479, "x": 276, "y": 189, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237497, "x": 277, "y": 190, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237515, "x": 277, "y": 191, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237532, "x": 277, "y": 192, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237548, "x": 278, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237569, "x": 278, "y": 194, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237601, "x": 278, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1412929237634, "x": 278, "y": 195, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237641, "x": 278, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237673, "x": 277, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237690, "x": 276, "y": 196, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237707, "x": 263, "y": 193, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237726, "x": 244, "y": 185, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237741, "x": 213, "y": 173, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237758, "x": 184, "y": 163, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237776, "x": 165, "y": 155, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237793, "x": 149, "y": 149, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237811, "x": 142, "y": 145, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237829, "x": 140, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237846, "x": 138, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237863, "x": 138, "y": 142, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237880, "x": 138, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237897, "x": 137, "y": 140, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237914, "x": 133, "y": 138, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237931, "x": 131, "y": 137, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237948, "x": 130, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237965, "x": 129, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929237983, "x": 129, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1412929238226, "x": 129, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238234, "x": 128, "y": 134, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238265, "x": 128, "y": 133, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238284, "x": 130, "y": 133, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238301, "x": 134, "y": 131, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238318, "x": 144, "y": 127, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238334, "x": 157, "y": 120, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238352, "x": 180, "y": 115, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238369, "x": 207, "y": 106, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238386, "x": 236, "y": 99, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238403, "x": 259, "y": 97, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238420, "x": 271, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238438, "x": 274, "y": 94, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929238455, "x": 275, "y": 94, "evt": { "button": 0 } },
|
||||
{ "type": "cut", "time": 1412929238856 },
|
||||
{ "type": "move", "time": 1412929239729, "x": 274, "y": 94, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239747, "x": 271, "y": 95, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239764, "x": 262, "y": 96, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239781, "x": 239, "y": 102, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239798, "x": 204, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239816, "x": 150, "y": 105, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239833, "x": 86, "y": 109, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1412929239851, "x": 30, "y": 117, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1412929239867, "x": -31, "y": 126, "evt": { "button": 0 } }
|
||||
]
|
||||
56
packages/noodl-editor/tests/recordings/undocutpaste.json
Normal file
@@ -0,0 +1,56 @@
|
||||
[
|
||||
{ "type": "over", "time": 1404236456261, "x": 4, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456262, "x": 4, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456278, "x": 9, "y": 146, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456295, "x": 11, "y": 145, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456395, "x": 11, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456411, "x": 11, "y": 143, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456429, "x": 11, "y": 141, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456447, "x": 12, "y": 139, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456464, "x": 13, "y": 137, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456481, "x": 14, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456499, "x": 15, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456515, "x": 17, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456533, "x": 20, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456550, "x": 23, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456567, "x": 27, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456584, "x": 28, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456601, "x": 31, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456619, "x": 32, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "down", "time": 1404236456681, "x": 32, "y": 135, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456843, "x": 33, "y": 136, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456860, "x": 39, "y": 144, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456877, "x": 49, "y": 157, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456894, "x": 68, "y": 179, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456911, "x": 90, "y": 204, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456928, "x": 116, "y": 232, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456946, "x": 143, "y": 259, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456970, "x": 161, "y": 278, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456980, "x": 172, "y": 289, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236456997, "x": 184, "y": 299, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457014, "x": 191, "y": 306, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457031, "x": 194, "y": 310, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457049, "x": 198, "y": 312, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457066, "x": 203, "y": 315, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457083, "x": 206, "y": 317, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457100, "x": 209, "y": 319, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457117, "x": 211, "y": 321, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457134, "x": 213, "y": 322, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457151, "x": 215, "y": 324, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457168, "x": 216, "y": 325, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457186, "x": 216, "y": 326, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457205, "x": 216, "y": 326, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457230, "x": 217, "y": 327, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236457253, "x": 217, "y": 328, "evt": { "button": 0 } },
|
||||
{ "type": "up", "time": 1404236457445, "x": 217, "y": 328, "evt": { "button": 0 } },
|
||||
{ "type": "cut", "time": 1404236457973 },
|
||||
{ "type": "paste", "time": 1404236458813 },
|
||||
{ "type": "move", "time": 1404236459383, "x": 214, "y": 328, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236459400, "x": 201, "y": 331, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236459417, "x": 185, "y": 332, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236459434, "x": 150, "y": 332, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236459451, "x": 100, "y": 332, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236459469, "x": 48, "y": 327, "evt": { "button": 0 } },
|
||||
{ "type": "move", "time": 1404236459486, "x": 7, "y": 321, "evt": { "button": 0 } },
|
||||
{ "type": "out", "time": 1404236459503, "x": -52, "y": 317, "evt": { "button": 0 } }
|
||||
]
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.8 MiB |
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="51px" height="19px" viewBox="0 0 51 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
|
||||
<title>badge/1 HR icon Copy 5</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Prototype-Flow-2-|-Prioritized" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="FLOW-3---Screen-1" transform="translate(-16.000000, -298.000000)">
|
||||
<g id="Group-12" transform="translate(16.000000, 294.000000)">
|
||||
<g id="badge/1-HR-icon" transform="translate(0.000000, 4.000000)">
|
||||
<rect id="background" fill="#FFFFFF" x="0" y="0" width="51" height="19" rx="3"></rect>
|
||||
<rect id="background" fill="#0DBA7F" opacity="0.149999991" x="0" y="0" width="51" height="19" rx="3"></rect>
|
||||
<g id="Group-10" stroke-width="1" transform="translate(-2.000000, 3.000000)" fill="#047850" font-size="11" font-weight="normal" line-spacing="12">
|
||||
<text id="text---title" font-family="Helvetica" letter-spacing="-0.2">
|
||||
<tspan x="20" y="10">1 hour</tspan>
|
||||
</text>
|
||||
<text id="text---title-copy" font-family="LastResort, .LastResort" letter-spacing="-0.3">
|
||||
<tspan x="6" y="9"></tspan>
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 342 B |
|
After Width: | Height: | Size: 543 B |
|
After Width: | Height: | Size: 821 B |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>18-clock-black</title>
|
||||
<g id="18-clock-black" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="🎨Edit-color-here!-2">
|
||||
<rect id="boundry" x="0" y="0" width="18" height="18"></rect>
|
||||
<path d="M9,17 C7.89816299,17 6.86081073,16.7890131 5.88791209,16.367033 C4.91501345,15.9450528 4.06813547,15.37363 3.34725275,14.6527473 C2.62637002,13.9318645 2.05494716,13.0849865 1.63296703,12.1120879 C1.2109869,11.1391893 1,10.101837 1,9 C1,7.89816299 1.2109869,6.86081073 1.63296703,5.88791209 C2.05494716,4.91501345 2.62637002,4.06813547 3.34725275,3.34725275 C4.06813547,2.62637002 4.91501345,2.05494716 5.88791209,1.63296703 C6.86081073,1.2109869 7.89816299,1 9,1 C10.101837,1 11.1391893,1.2109869 12.1120879,1.63296703 C13.0849865,2.05494716 13.9318645,2.62637002 14.6527473,3.34725275 C15.37363,4.06813547 15.9450528,4.91501345 16.367033,5.88791209 C16.7890131,6.86081073 17,7.89816299 17,9 C17,10.101837 16.7890131,11.1391893 16.367033,12.1120879 C15.9450528,13.0849865 15.37363,13.9318645 14.6527473,14.6527473 C13.9318645,15.37363 13.0849865,15.9450528 12.1120879,16.367033 C11.1391893,16.7890131 10.101837,17 9,17 Z M9,2.0021978 C8.03882303,2.0021978 7.13040721,2.18388097 6.27472527,2.54725275 C5.43076501,2.91062453 4.68938048,3.41171842 4.05054945,4.05054945 C3.41171842,4.68938048 2.91062453,5.43076501 2.54725275,6.27472527 C2.18388097,7.13040721 2.0021978,8.03882303 2.0021978,9 C2.0021978,9.96117697 2.18388097,10.8695928 2.54725275,11.7252747 C2.91062453,12.569235 3.41171842,13.3106195 4.05054945,13.9494505 C4.68938048,14.5882816 5.43076501,15.0893755 6.27472527,15.4527473 C7.13040721,15.816119 8.03882303,15.9978022 9,15.9978022 C9.96117697,15.9978022 10.8695928,15.816119 11.7252747,15.4527473 C12.569235,15.0893755 13.3106195,14.5882816 13.9494505,13.9494505 C14.5882816,13.3106195 15.0893755,12.569235 15.4527473,11.7252747 C15.816119,10.8695928 15.9978022,9.96117697 15.9978022,9 C15.9978022,8.03882303 15.816119,7.13040721 15.4527473,6.27472527 C15.0893755,5.43076501 14.5882816,4.68938048 13.9494505,4.05054945 C13.3106195,3.41171842 12.569235,2.91062453 11.7252747,2.54725275 C10.8695928,2.18388097 9.96117697,2.0021978 9,2.0021978 Z M9,5.5010989 C9,5.36043886 9.04981635,5.24029354 9.14945055,5.14065934 C9.24908475,5.04102514 9.36336932,4.99120879 9.49230769,4.99120879 C9.63296774,4.99120879 9.75311305,5.04102514 9.85274725,5.14065934 C9.95238145,5.24029354 10.0021978,5.36043886 10.0021978,5.5010989 L10.0021978,10.0021978 L6.5032967,10.0021978 C6.36263666,10.0021978 6.24249134,9.95238145 6.14285714,9.85274725 C6.04322295,9.75311305 5.99340659,9.63296774 5.99340659,9.49230769 C5.99340659,9.36336932 6.04322295,9.24908475 6.14285714,9.14945055 C6.24249134,9.04981635 6.36263666,9 6.5032967,9 L9,9 L9,5.5010989 Z" id="🎨Edit-color-here!" fill="#000000"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |