mirror of
https://github.com/xibyte/jsketcher
synced 2026-02-08 16:32:15 +01:00
adding first integration tests for segments
This commit is contained in:
parent
d2971a681b
commit
8330d4b91d
12 changed files with 264 additions and 62 deletions
|
|
@ -10,6 +10,7 @@ import '../css/app.less'
|
|||
|
||||
function initializeSketcherApplication() {
|
||||
var app = new App2D();
|
||||
window._TCAD_APP = app;
|
||||
var sketchId = app.getSketchId();
|
||||
if (sketchId == App2D.STORAGE_PREFIX + '__sample2D__') {
|
||||
var sample = '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[{"id":0,"_class":"TCAD.TWO.DiameterDimension","obj":90},{"id":1,"_class":"TCAD.TWO.DiameterDimension","obj":95},{"id":2,"_class":"TCAD.TWO.DiameterDimension","obj":42},{"id":3,"_class":"TCAD.TWO.Dimension","a":5,"b":8,"flip":false},{"id":4,"_class":"TCAD.TWO.DiameterDimension","obj":105}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":11,"_class":"TCAD.TWO.Segment","points":[[5,[6,110.1295615870824],[7,313.66509156975803]],[8,[9,419.44198895058975],[10,516.7065215258621]]]},{"id":18,"_class":"TCAD.TWO.Segment","points":[[12,[13,489.1218947877601],[14,477.98601743930897]],[15,[16,481.90945628911174],[17,182.9391540301952]]]},{"id":25,"_class":"TCAD.TWO.Segment","points":[[19,[20,427.6872468325118],[21,163.96220645927505]],[22,[23,349.9023145352797],[24,256.7344291384989]]]},{"id":32,"_class":"TCAD.TWO.Segment","points":[[26,[27,306.81261277555075],[28,273.1404656521002]],[29,[30,135.09050734792822],[31,247.98348666778958]]]},{"id":42,"_class":"TCAD.TWO.Arc","points":[[33,[34,489.1218947877601],[35,477.98601743930897]],[36,[37,419.44198895058975],[38,516.7065215258621]],[39,[40,444.1353623657045],[41,479.08688157090376]]]},{"id":53,"_class":"TCAD.TWO.Arc","points":[[44,[45,427.6872468325118],[46,163.96220645927505]],[47,[48,481.90945628911174],[49,182.9391540301952]],[50,[51,451.2148840882273],[52,183.68960424767275]]]},{"id":64,"_class":"TCAD.TWO.Arc","points":[[55,[56,349.9023145352797],[57,256.7344291384989]],[58,[59,306.81261277555075],[60,273.1404656521002]],[61,[62,313.6665992835383],[63,226.35256652594512]]]},{"id":75,"_class":"TCAD.TWO.Arc","points":[[66,[67,110.1295615870824],[68,313.66509156975803]],[69,[70,135.09050734792822],[71,247.98348666778958]],[72,[73,129.8749213918784],[74,283.58516027516237]]]},{"id":80,"_class":"TCAD.TWO.Circle","c":[77,[78,444.1353623657045],[79,479.08688157090376]],"r":17},{"id":85,"_class":"TCAD.TWO.Circle","c":[82,[83,451.2148840882273],[84,183.68960424767275]],"r":17},{"id":90,"_class":"TCAD.TWO.Circle","c":[87,[88,129.8749213918784],[89,283.58516027516237]],"r":17},{"id":95,"_class":"TCAD.TWO.Circle","c":[92,[93,364.7627927122075],[94,358.27520724354514]],"r":50},{"id":100,"_class":"TCAD.TWO.Circle","c":[97,[98,450.6425914465028],[99,356.1758703461729]],"r":13},{"id":105,"_class":"TCAD.TWO.Circle","c":[102,[103,281.1241663120215],[104,360.3197585470608]],"r":13}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[{"id":113,"_class":"TCAD.TWO.Segment","points":[[107,[108,366.96497096679207],[109,448.36204633886825]],[110,[111,362.6842565514955],[112,273.2463262825022]]]},{"id":120,"_class":"TCAD.TWO.Segment","points":[[114,[115,254.60331148100178],[116,360.9680624545806]],[117,[118,474.9222739434132],[119,355.5823520325097]]]}]}],"constraints":[["Tangent",[42,18]],["Tangent",[42,11]],["coi",[33,12]],["coi",[36,8]],["Tangent",[53,25]],["Tangent",[53,18]],["coi",[44,19]],["coi",[47,15]],["Tangent",[64,25]],["Tangent",[64,32]],["coi",[55,22]],["coi",[58,26]],["Tangent",[75,11]],["Tangent",[75,32]],["coi",[66,5]],["coi",[69,29]],["coi",[77,39]],["coi",[82,50]],["coi",[87,72]],["RR",[80,85]],["RR",[85,90]],["parallel",[113,18]],["perpendicular",[120,113]],["Symmetry",[92,120]],["PointOnLine",[92,113]],["PointOnLine",[102,120]],["PointOnLine",[97,120]],["RR",[105,100]]]}';
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
export default {
|
||||
testSaveLoad: function() {
|
||||
|
||||
}
|
||||
}
|
||||
7
web/test/cases/arc.js
Normal file
7
web/test/cases/arc.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
testSaveLoad: function(env) {
|
||||
|
||||
|
||||
env.done();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import * as test from '../test'
|
||||
|
||||
export default {
|
||||
testSaveLoad: function() {
|
||||
test.fail('Nothing works');
|
||||
}
|
||||
}
|
||||
86
web/test/cases/segment.js
Normal file
86
web/test/cases/segment.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import * as test from '../test'
|
||||
import {TestMouseEvent} from '../utils/mouse-event'
|
||||
|
||||
function addSegment(app, aX, aY, bX, bY) {
|
||||
app.actions['addSegment'].action();
|
||||
app.viewer.toolManager.tool.mouseup(new TestMouseEvent(aX, aY));
|
||||
app.viewer.toolManager.tool.mousemove(new TestMouseEvent(bX, bY));
|
||||
app.viewer.toolManager.tool.mouseup(new TestMouseEvent(bX, bY));
|
||||
app.viewer.toolManager.releaseControl();
|
||||
}
|
||||
|
||||
function click(tool, x, y) {
|
||||
tool.mousedown(new TestMouseEvent(x, y));
|
||||
tool.mouseup(new TestMouseEvent(x, y));
|
||||
}
|
||||
|
||||
export default {
|
||||
testSegmentWizard: function(env) {
|
||||
const win = test.emptySketch((win, app) => {
|
||||
env.assertEquals(0, app.viewer.activeLayer.objects.length);
|
||||
addSegment(app, 10, 10, 100, 100);
|
||||
env.assertEquals(1, app.viewer.activeLayer.objects.length);
|
||||
const segment = app.viewer.activeLayer.objects[0];
|
||||
env.assertEquals('TCAD.TWO.Segment', segment._class);
|
||||
env.assertPoint2DEquals(10, 10, segment.a);
|
||||
env.assertPoint2DEquals(101, 100, segment.b);
|
||||
env.done();
|
||||
});
|
||||
},
|
||||
|
||||
testSaveLoad: function(env) {
|
||||
test.emptySketch((win, app) => {
|
||||
env.assertEquals(0, app.viewer.activeLayer.objects.length);
|
||||
addSegment(app, 10, 10, 100, 100);
|
||||
app.actions['save'].action();
|
||||
test.sketch((win, app) => {
|
||||
env.assertEquals(1, app.viewer.activeLayer.objects.length);
|
||||
const segment = app.viewer.activeLayer.objects[0];
|
||||
env.assertEquals('TCAD.TWO.Segment', segment._class);
|
||||
env.done();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
testSelection: function(env) {
|
||||
test.emptySketch((win, app) => {
|
||||
addSegment(app, 10, 10, 100, 100);
|
||||
env.assertEquals(0, app.viewer.selected.length);
|
||||
click(app.viewer.toolManager.tool, 50, 50);
|
||||
env.assertEquals(1, app.viewer.selected.length);
|
||||
env.done();
|
||||
});
|
||||
},
|
||||
|
||||
testSelectionNeighborhood: function(env) {
|
||||
test.emptySketch((win, app) => {
|
||||
addSegment(app, 10, 10, 100, 100);
|
||||
env.assertEquals(0, app.viewer.selected.length);
|
||||
// this point technically isn't on the line but should trigger the selection
|
||||
click(app.viewer.toolManager.tool, 55, 50);
|
||||
env.assertEquals(1, app.viewer.selected.length);
|
||||
env.done();
|
||||
});
|
||||
},
|
||||
|
||||
testSnap: function(env) {
|
||||
test.emptySketch((win, app) => {
|
||||
addSegment(app, 10, 10, 100, 100);
|
||||
env.assertEquals(0, app.viewer.selected.length);
|
||||
// this point technically isn't on the line but should trigger the selection
|
||||
click(app.viewer.toolManager.tool, 55, 50);
|
||||
env.assertEquals(1, app.viewer.selected.length);
|
||||
env.done();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function collectObjects(visitable) {
|
||||
const objects = [];
|
||||
visitable.accept((o) => {
|
||||
objects.push(o);
|
||||
});
|
||||
return objects;
|
||||
}
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
<body>
|
||||
<div id="control-bar" class="page-row">
|
||||
<button id="run-button"><i class="fa fa-play"></i></button>
|
||||
<button id="pause-button"><i class="fa fa-pause"></i></button>
|
||||
<!--<button id="pause-button"><i class="fa fa-pause"></i></button>-->
|
||||
<span id="status" style="float: right">0 run / 0 passed / 0 failures</span>
|
||||
</div>
|
||||
<iframe id="main-sandbox"></iframe>
|
||||
<div id="sandbox"></div>
|
||||
<div class="page-row" id="test-list">
|
||||
</div>
|
||||
<div id="popup-menu" style="position: absolute; display: none;"></div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import TestList from './tmpl/test-list.html'
|
|||
import '../app/utils/jqueryfy'
|
||||
import suites from './suites'
|
||||
import {Menu} from './menu'
|
||||
import {AssertionError} from './test'
|
||||
import {TestEnv} from './test'
|
||||
import DurationFormat from './utils/duration-format'
|
||||
|
||||
|
||||
$(() => {
|
||||
const runBtn = $('#run-button');
|
||||
|
|
@ -13,71 +15,87 @@ $(() => {
|
|||
|
||||
runBtn.click(() => {
|
||||
run();
|
||||
disableBtn(runBtn);
|
||||
enableBtn(pauseBtn);
|
||||
//disableBtn(runBtn);
|
||||
//enableBtn(pauseBtn);
|
||||
});
|
||||
|
||||
pauseBtn.click(() => {
|
||||
disableBtn(pauseBtn);
|
||||
enableBtn(runBtn);
|
||||
});
|
||||
console.log(suites);
|
||||
$('#test-list').html(TestList({suites}));
|
||||
new Menu(ACTIONS);
|
||||
});
|
||||
|
||||
const queue = [];
|
||||
let running = false;
|
||||
|
||||
function runSuite(name) {
|
||||
function scheduleSuite(name) {
|
||||
const testCases = suites[name];
|
||||
let success = true;
|
||||
for (let testCase of testCases) {
|
||||
if (!runTestCase(testCase, name + ':' +testCase.name)) {
|
||||
success = false;
|
||||
}
|
||||
scheduleTestCase(testCase, name + ':' +testCase.name);
|
||||
}
|
||||
updateIcon($('#suite-' + name), success);
|
||||
//updateIcon($('#suite-' + name), success);
|
||||
}
|
||||
|
||||
function runTestCase(testCase, caseId) {
|
||||
let success = true;
|
||||
for (let test of testCase.tests) {
|
||||
if (!runTest(test, caseId + ':' + test.name)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
updateIcon($('#case-' + caseId.replace(/:/g, '-')), success);
|
||||
function scheduleTestCase(testCase, caseId) {
|
||||
testCase.tests.forEach(test => scheduleTest(test, caseId + ':' + test.name));
|
||||
//updateIcon($('#case-' + caseId.replace(/:/g, '-')), success);
|
||||
}
|
||||
|
||||
function runTest(test, testId) {
|
||||
let success = true;
|
||||
function scheduleTest(test, id) {
|
||||
queue.push({
|
||||
id,
|
||||
func: test
|
||||
});
|
||||
}
|
||||
|
||||
function pokeQueue() {
|
||||
if (running) return;
|
||||
//let ui refresh
|
||||
setTimeout(() => {
|
||||
if (queue.length != 0) {
|
||||
const test = queue.shift();
|
||||
running = true;
|
||||
runTest(test.func, test.id, (testSuccess) => {
|
||||
running = false;
|
||||
pokeQueue();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function runTest(test, testId, callback) {
|
||||
let testDom = $('#test-' + testId.replace(/:/g, '-'));
|
||||
testDom.find('.status').hide();
|
||||
testDom.find('.progress').show();
|
||||
try {
|
||||
test();
|
||||
} catch (e) {
|
||||
success = false;
|
||||
if (e instanceof AssertionError) {
|
||||
testDom.find('.result').text(e.msg);
|
||||
const env = new TestEnv((env) => {
|
||||
testDom.find('.progress').hide();
|
||||
testDom.find('.status').show();
|
||||
let success = env.finished && !env.failed;
|
||||
updateIcon(testDom, success);
|
||||
let result = 'took: ' + DurationFormat(env.took);
|
||||
if (env.error) {
|
||||
result += ' ' + env.error;
|
||||
}
|
||||
}
|
||||
testDom.find('.progress').hide();
|
||||
testDom.find('.status').show();
|
||||
updateIcon(testDom, success);
|
||||
return success;
|
||||
testDom.find('.result').html(result);
|
||||
callback(success);
|
||||
});
|
||||
test(env);
|
||||
}
|
||||
|
||||
function run() {
|
||||
queue.length = 0;
|
||||
for (let suite of Object.keys(suites)) {
|
||||
runSuite(suite);
|
||||
scheduleSuite(suite);
|
||||
}
|
||||
pokeQueue();
|
||||
}
|
||||
|
||||
function pause() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function updateIcon(dom, success) {
|
||||
dom.find('.status').addClass(success ? 'status-success' : 'status-fail');
|
||||
}
|
||||
|
|
@ -104,7 +122,11 @@ function enableBtn(btn) {
|
|||
const ACTIONS = {
|
||||
RunSuite: {
|
||||
label: "Run Suite",
|
||||
invoke: (target) => runSuite(target.data('suiteName'))
|
||||
invoke: (target) => {
|
||||
queue.length = 0;
|
||||
scheduleSuite(target.data('suiteName'));
|
||||
pokeQueue();
|
||||
}
|
||||
},
|
||||
|
||||
RunTestCase: {
|
||||
|
|
@ -112,7 +134,9 @@ const ACTIONS = {
|
|||
invoke: (target) => {
|
||||
var testCaseIdStr = target.data('testCaseId');
|
||||
const testCaseId = testCaseIdStr.split(':');
|
||||
runTestCase(findTestCaseById(testCaseId), testCaseIdStr);
|
||||
queue.length = 0;
|
||||
scheduleTestCase(findTestCaseById(testCaseId), testCaseIdStr);
|
||||
pokeQueue();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -121,7 +145,9 @@ const ACTIONS = {
|
|||
invoke: (target) => {
|
||||
var testIdStr = target.data('testId');
|
||||
const testId = testIdStr.split(':');
|
||||
runTest(findTestById(testId), testIdStr)
|
||||
queue.length = 0;
|
||||
scheduleTest(findTestById(testId), testIdStr);
|
||||
pokeQueue();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,11 +3,18 @@ body {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#main-sandbox {
|
||||
#sandbox {
|
||||
border: 3px plum solid;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 60%;
|
||||
background-color: #233930;
|
||||
}
|
||||
|
||||
#sandbox iframe {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-row {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export default {
|
||||
SketcherIO: [
|
||||
TestCase('segment-io'),
|
||||
TestCase('arc-io')
|
||||
TestCase('segment'),
|
||||
TestCase('arc')
|
||||
],
|
||||
|
||||
SketcherTools: [
|
||||
|
|
|
|||
|
|
@ -1,15 +1,71 @@
|
|||
|
||||
export function fail(msg, optionalMsg) {
|
||||
optionalMsg = (optionalMsg === undefined ? '' : ' ' + optionalMsg);
|
||||
throw new AssertionError(msg + optionalMsg);
|
||||
export function FailError(msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
export function assertEquals(expected, actual, msg) {
|
||||
if (expected !== actual) {
|
||||
fail('assertEquals: Expected: ' + expected + ' but was ' + actual, msg);
|
||||
export class TestEnv {
|
||||
|
||||
constructor(callback) {
|
||||
this.failed = false;
|
||||
this.finished = false;
|
||||
this.error = undefined;
|
||||
this.callback = callback;
|
||||
this.took = performance.now()
|
||||
}
|
||||
|
||||
done() {
|
||||
this.finished = true;
|
||||
this.took = performance.now() - this.took;
|
||||
this.callback(this);
|
||||
}
|
||||
|
||||
fail(msg, optionalMsg) {
|
||||
this.failed = true;
|
||||
this.error = msg + (optionalMsg === undefined ? '' : ' ' + optionalMsg);
|
||||
this.done();
|
||||
throw new FailError(this.error);
|
||||
}
|
||||
|
||||
assertTrue(stmt, msg) {
|
||||
if (!stmt) {
|
||||
this.fail('assertTrue fails.', msg);
|
||||
}
|
||||
}
|
||||
assertEquals(expected, actual, msg) {
|
||||
if (expected !== actual) {
|
||||
this.fail('assertEquals: Expected: ' + expected + ' but was ' + actual, msg);
|
||||
}
|
||||
}
|
||||
|
||||
assertPoint2DEquals(expectedX, expectedY, actial, msg) {
|
||||
if (actial.x !== expectedX || actial.y !== expectedY) {
|
||||
this.fail('assertPoint2DEquals: Expected: (' + expectedX + ', ' + expectedY + ') but was (' + actial.x + ', ' + actial.y + ')' , msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function AssertionError(msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
export function load(url, callback) {
|
||||
const sandbox = $('#sandbox');
|
||||
sandbox.empty();
|
||||
const frame = $('<iframe>');
|
||||
sandbox.append(frame);
|
||||
$(function() { // fire event when iframe is ready
|
||||
frame.load(function() {
|
||||
const win = frame.get(0).contentWindow;
|
||||
callback(win, win._TCAD_APP)
|
||||
});
|
||||
});
|
||||
frame.attr('src', window.location.origin + url)
|
||||
}
|
||||
|
||||
const TEST_SKETCH_PROJECT = '$$$__test__$$$';
|
||||
const STORAGE_PREFIX_SKETCH = "TCAD.projects.";
|
||||
|
||||
export function emptySketch(callback) {
|
||||
localStorage.removeItem(STORAGE_PREFIX_SKETCH + TEST_SKETCH_PROJECT);
|
||||
sketch(callback);
|
||||
}
|
||||
|
||||
export function sketch(callback) {
|
||||
load('/sketcher.html#' + TEST_SKETCH_PROJECT, callback);
|
||||
}
|
||||
|
|
|
|||
11
web/test/utils/duration-format.js
Normal file
11
web/test/utils/duration-format.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export default function(millis){
|
||||
if (millis < 1000) {
|
||||
return fixed(millis) + "ms";
|
||||
} else {
|
||||
return fixed(millis / 1000) + "s";
|
||||
}
|
||||
};
|
||||
|
||||
function fixed(v) {
|
||||
return v.toFixed(2);
|
||||
}
|
||||
20
web/test/utils/mouse-event.js
Normal file
20
web/test/utils/mouse-event.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
export function TestMouseEvent(x, y, type) {
|
||||
this.type = type ? type : 'click';
|
||||
this.canBubble = true;
|
||||
this.cancelable = true;
|
||||
this.detail = 1;
|
||||
this.screenX = x;
|
||||
this.screenY = y;
|
||||
this.clientX = this.screenX;
|
||||
this.clientY = this.screenY;
|
||||
this.pageX = this.screenX;
|
||||
this.pageY = this.screenY;
|
||||
this.offsetX = this.screenX;
|
||||
this.offsetY = this.screenY;
|
||||
this.ctrlKey = false;
|
||||
this.altKey = false;
|
||||
this.shiftKey = false;
|
||||
this.metaKey = false;
|
||||
this.button = 0;
|
||||
this.relatedTarget = null;
|
||||
}
|
||||
Loading…
Reference in a new issue