Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions browser/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ var clicks = [
}
var selector = this.selector;
FuncUnit.add({
method: function(success, error){
method: async function(success, error){
options = options || {};
syn("_" + name, this.bind[0], options, success);
await syn[name](this.bind[0], options);
},
success: success,
error: "Could not " + name + " '" + this.selector+"'",
Expand Down Expand Up @@ -146,9 +146,8 @@ $.extend(FuncUnit.prototype, {
text = "[ctrl]a[ctrl-up]\b"
}
FuncUnit.add({
method : function(success, error){
syn("_type", this.bind[0], text, success);

method : async function(success, error){
await syn.type(this.bind[0], text);
},
success : success,
error : "Could not type " + text + " into " + this.selector,
Expand Down Expand Up @@ -177,9 +176,8 @@ $.extend(FuncUnit.prototype, {
keys = "[ctrl]a[ctrl-up]\b"
}
FuncUnit.add({
method : function(success, error){
syn("_type", this.bind[0], keys, success);

method : async function(success, error){
await syn.type(this.bind[0], keys);
},
success : success,
error : "Could not send the keys " + keys + " into " + this.selector,
Expand Down Expand Up @@ -266,8 +264,8 @@ $.extend(FuncUnit.prototype, {

var selector = this.selector;
FuncUnit.add({
method: function(success, error){
syn("_drag", this.bind[0], options, success);
method: async function(success, error){
await syn.drag(this.bind[0], options);
},
success: success,
error: "Could not drag " + this.selector,
Expand Down Expand Up @@ -334,8 +332,8 @@ $.extend(FuncUnit.prototype, {

var selector = this.selector;
FuncUnit.add({
method: function(success, error){
syn("_move", this.bind[0], options, success);
method: async function(success, error){
await syn.move(this.bind[0], options);
},
success: success,
error: "Could not move " + this.selector,
Expand Down
81 changes: 81 additions & 0 deletions new-src/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const syn = require("syn");

const funcUnitActions = {
click(){
return simpleAsyncAction(this, syn.click);
},

rightClick() {
return simpleAsyncAction(this, syn.rightClick);
},

dblClick() {
return simpleAsyncAction(this, syn.dblclick);
},

scroll(direction, amount) {
let func;

if (direction === 'left' || direction === 'right') {
func = function (el) {
el.scrollLeft = amount;
return el;
}
}

if (direction === 'top' || direction === 'bottom') {
func = function (el) {
el.scrollTop = amount;
return el;
}
}

return simpleSyncAction(this, func);
},

drag() {
return simpleAsyncActionWithArgs(this, syn.drag, arguments);
},

move() {
return simpleAsyncActionWithArgs(this, syn.move, arguments);
},

type(text) {
this.click();
return simpleAsyncActionWithArgs(this, syn.type, arguments);
},

sendKeys(text) {
return simpleAsyncActionWithArgs(this, syn.type, arguments);
}
};


// Helper functions

function simpleAsyncActionWithArgs(elementPromise, action, args) {
return new elementPromise.constructor(function simpleActionWithArgs(resolve, reject) {
elementPromise.then(function (element) {
action(element, ...args).then(() => resolve(element), reject);
}, reject);
});
}

function simpleAsyncAction(elementPromise, action) {
return new elementPromise.constructor(function simpleAction(resolve, reject) {
elementPromise.then(function (element){
action(element).then(()=> resolve(element), reject);
}, reject);
});
}

function simpleSyncAction(elementPromise, action) {
return new elementPromise.constructor(function simpleAction(resolve, reject) {
elementPromise.then(function (element){
resolve( action(element) );
}, reject);
});
}

module.exports = funcUnitActions;
151 changes: 151 additions & 0 deletions new-src/core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
const Sizzle = require("sizzle");

const {
resolveWhenTrue,
makeExecutorToResolveWhenTrue
} = require('./helpers');

const funcUnitActions = require('./actions');
const funcUnitGetters = require('./getters');
const funcUnitTraversers = require('./traversers');

const funcUnitPrototypeMethods = {
...funcUnitActions,
...funcUnitGetters,
...funcUnitTraversers
};

function makeFuncUnit(defaultWindow) {

function FuncUnit(selector, context) {
let executor;
if(typeof selector === "string") {
let win = getWindow(selector, context || FuncUnit.defaultWindow);

executor = makeExecutorToResolveWhenTrue({
tester: function(){
var documentElement = win.document.documentElement;

if(!documentElement) {
return undefined;
}
var results = Sizzle(selector, documentElement);
// contains will return multiple elements nested inside each other, this helps take the right
// one.

return takeFirstDeepestChild(results);
},
rejectReason: () => new Error("Unable to find "+selector)
})
} else if(typeof selector === "function") {
executor = selector;
} else {
throw "arguments not understood";
}
return Reflect.construct(Promise, [executor], FuncUnit);
};

FuncUnit.defaultWindow = defaultWindow;

Object.assign(
FuncUnit,
Object.fromEntries(
Reflect.ownKeys(Promise)
.filter(key => key !== "length" && key !== "name")
.map(key => [key, Promise[key]])
)
);
// Create the prototype, add methods to it
FuncUnit.prototype = Object.create(Promise.prototype);
FuncUnit.prototype.constructor = FuncUnit;

Object.assign(FuncUnit.prototype, funcUnitPrototypeMethods);

Object.assign(FuncUnit, funcUnitStaticMethods);
return FuncUnit;
}

const funcUnitStaticMethods = {
async useWindow(url){
var width = window.innerWidth;
this.defaultWindow = window.open(url, "funcunit", "height=1000,toolbar=yes,status=yes,left="+width/4);

if(this.defaultWindow && this.defaultWindow.___FUNCUNIT_OPENED) {
this.defaultWindow.close();
this.defaultWindow = window.open(url, "funcunit", "height=1000,toolbar=yes,status=yes,left="+width/4);
}
let stealDone = false, ready = false;

setTimeout(() => ready = true, 123);

await resolveWhenTrue({
tester: () => {


// make sure there is a document
if(!this.defaultWindow.document.documentElement) {
return;
}
if( this.defaultWindow.document.readyState !== "complete" ||
this.defaultWindow.location.href === "about:blank" ||
!this.defaultWindow.document.body ) {
return;
}
this.defaultWindow.___FUNCUNIT_OPENED = true;

// wait for steal to fully load
if( this.defaultWindow.steal ) {
this.defaultWindow.steal.done().then(() => {
stealDone = true;
});
} else {
stealDone = true;
}
return stealDone && ready;
}
})
return this;
}
}

function takeFirstDeepestChild(elements){
var cur = elements[0];
var index = 1;
var next;
while(next = elements[index]) {
if(!next) {
return cur;
}
if(! cur.contains(next) ) {
return cur;
} else {
cur = next;
index++;
}
}
return cur;
}

function getWindowFromElement(element){
const doc = element.ownerDocument;
return doc.defaultView || doc.parentWindow;
}

function getWindow(element, context) {

if (element.nodeName) {
return getWindowFromElement(element);
} else {
if (!context) {
return window;
} else if (context.nodeName === "#document") {
return getWindowFromElement(element);
} else if (context.self === context) {
return context;
} else {
throw new Error("can't find window")
}
}
}

module.exports = makeFuncUnit();
Loading