2 Copyright (C) 2008 Trolltech ASA
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
21 #include <QtTest/QtTest>
26 #include <qwebframe.h>
27 #include <qwebhistory.h>
34 * Starts an event loop that runs until the given signal is received.
35 Optionally the event loop
36 * can return earlier on a timeout.
38 * \return \p true if the requested signal was received
41 static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
44 QObject::connect(obj, signal, &loop, SLOT(quit()));
46 QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
48 QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
49 timer.setSingleShot(true);
53 return timeoutSpy.isEmpty();
56 /* Mostly a test for the JavaScript related parts of QWebFrame */
62 Q_DECLARE_METATYPE(CustomType)
64 Q_DECLARE_METATYPE(QBrush*)
65 Q_DECLARE_METATYPE(QObjectList)
66 Q_DECLARE_METATYPE(QList<int>)
67 Q_DECLARE_METATYPE(Qt::BrushStyle)
68 Q_DECLARE_METATYPE(QVariantList)
69 Q_DECLARE_METATYPE(QVariantMap)
71 class MyQObject : public QObject
75 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
76 Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
77 Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
78 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
79 Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
80 Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
81 Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
82 Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
83 Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
84 Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
85 Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
86 Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
87 Q_ENUMS(Policy Strategy)
108 AllAbility = FooAbility | BarAbility | BazAbility
111 Q_DECLARE_FLAGS(Ability, AbilityFlag)
113 MyQObject(QObject* parent = 0)
116 m_variantValue(QLatin1String("foo")),
117 m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
118 m_stringValue(QLatin1String("bar")),
119 m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
120 m_brushValue(QColor(10, 20, 30, 40)),
121 m_hiddenValue(456.0),
122 m_writeOnlyValue(789),
123 m_readOnlyValue(987),
124 m_qtFunctionInvoked(-1) { }
128 int intProperty() const {
131 void setIntProperty(int value) {
135 QVariant variantProperty() const {
136 return m_variantValue;
138 void setVariantProperty(const QVariant &value) {
139 m_variantValue = value;
142 QVariantList variantListProperty() const {
143 return m_variantListValue;
145 void setVariantListProperty(const QVariantList &value) {
146 m_variantListValue = value;
149 QString stringProperty() const {
150 return m_stringValue;
152 void setStringProperty(const QString &value) {
153 m_stringValue = value;
156 QStringList stringListProperty() const {
157 return m_stringListValue;
159 void setStringListProperty(const QStringList &value) {
160 m_stringListValue = value;
163 QByteArray byteArrayProperty() const {
164 return m_byteArrayValue;
166 void setByteArrayProperty(const QByteArray &value) {
167 m_byteArrayValue = value;
170 QBrush brushProperty() const {
173 Q_INVOKABLE void setBrushProperty(const QBrush &value) {
174 m_brushValue = value;
177 double hiddenProperty() const {
178 return m_hiddenValue;
180 void setHiddenProperty(double value) {
181 m_hiddenValue = value;
184 int writeOnlyProperty() const {
185 return m_writeOnlyValue;
187 void setWriteOnlyProperty(int value) {
188 m_writeOnlyValue = value;
191 int readOnlyProperty() const {
192 return m_readOnlyValue;
195 QKeySequence shortcut() const {
198 void setShortcut(const QKeySequence &seq) {
202 CustomType propWithCustomType() const {
205 void setPropWithCustomType(const CustomType &c) {
209 int qtFunctionInvoked() const {
210 return m_qtFunctionInvoked;
213 QVariantList qtFunctionActuals() const {
217 void resetQtFunctionInvoked() {
218 m_qtFunctionInvoked = -1;
222 Q_INVOKABLE void myInvokable() {
223 m_qtFunctionInvoked = 0;
225 Q_INVOKABLE void myInvokableWithIntArg(int arg) {
226 m_qtFunctionInvoked = 1;
229 Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) {
230 m_qtFunctionInvoked = 2;
233 Q_INVOKABLE void myInvokableWithFloatArg(float arg) {
234 m_qtFunctionInvoked = 3;
237 Q_INVOKABLE void myInvokableWithDoubleArg(double arg) {
238 m_qtFunctionInvoked = 4;
241 Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) {
242 m_qtFunctionInvoked = 5;
245 Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) {
246 m_qtFunctionInvoked = 6;
247 m_actuals << arg1 << arg2;
249 Q_INVOKABLE int myInvokableReturningInt() {
250 m_qtFunctionInvoked = 7;
253 Q_INVOKABLE qlonglong myInvokableReturningLongLong() {
254 m_qtFunctionInvoked = 39;
257 Q_INVOKABLE QString myInvokableReturningString() {
258 m_qtFunctionInvoked = 8;
259 return QLatin1String("ciao");
261 Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload
262 m_qtFunctionInvoked = 9;
263 m_actuals << arg1 << arg2;
265 Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) {
266 m_qtFunctionInvoked = 10;
269 Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) {
270 m_qtFunctionInvoked = 36;
273 Q_INVOKABLE Policy myInvokableReturningEnum() {
274 m_qtFunctionInvoked = 37;
277 Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() {
278 m_qtFunctionInvoked = 38;
281 Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() {
282 m_qtFunctionInvoked = 11;
283 return QVector<int>();
285 Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) {
286 m_qtFunctionInvoked = 12;
288 Q_INVOKABLE QObject* myInvokableReturningQObjectStar() {
289 m_qtFunctionInvoked = 13;
292 Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) {
293 m_qtFunctionInvoked = 14;
294 m_actuals << qVariantFromValue(lst);
297 Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) {
298 m_qtFunctionInvoked = 15;
302 Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) {
303 m_qtFunctionInvoked = 16;
307 Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) {
308 m_qtFunctionInvoked = 17;
309 m_actuals << qVariantFromValue(lst);
312 Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) {
313 m_qtFunctionInvoked = 18;
314 m_actuals << qVariantFromValue(obj);
317 Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) {
318 m_qtFunctionInvoked = 19;
319 m_actuals << qVariantFromValue(brush);
322 Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) {
323 m_qtFunctionInvoked = 43;
324 m_actuals << qVariantFromValue(style);
326 Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) {
327 m_qtFunctionInvoked = 44;
328 m_actuals << qVariantFromValue(arg);
330 Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) {
331 m_qtFunctionInvoked = 45;
332 m_actuals << qVariantFromValue(arg);
334 Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) {
335 m_qtFunctionInvoked = 46;
336 m_actuals << qVariantFromValue(arg);
338 Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") {
339 m_qtFunctionInvoked = 47;
340 m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2);
342 Q_INVOKABLE QObject& myInvokableReturningRef() {
343 m_qtFunctionInvoked = 48;
346 Q_INVOKABLE const QObject& myInvokableReturningConstRef() const {
347 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
350 Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
351 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
352 m_actuals << qVariantFromValue(arg);
354 Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
355 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
356 m_actuals << qVariantFromValue(arg);
359 void emitMySignal() {
362 void emitMySignalWithIntArg(int arg) {
363 emit mySignalWithIntArg(arg);
365 void emitMySignal2(bool arg) {
368 void emitMySignal2() {
371 void emitMySignalWithDateTimeArg(QDateTime dt) {
372 emit mySignalWithDateTimeArg(dt);
374 void emitMySignalWithRegexArg(QRegExp r) {
375 emit mySignalWithRegexArg(r);
380 m_qtFunctionInvoked = 20;
382 void mySlotWithIntArg(int arg) {
383 m_qtFunctionInvoked = 21;
386 void mySlotWithDoubleArg(double arg) {
387 m_qtFunctionInvoked = 22;
390 void mySlotWithStringArg(const QString &arg) {
391 m_qtFunctionInvoked = 23;
395 void myOverloadedSlot() {
396 m_qtFunctionInvoked = 24;
398 void myOverloadedSlot(QObject* arg) {
399 m_qtFunctionInvoked = 41;
402 void myOverloadedSlot(bool arg) {
403 m_qtFunctionInvoked = 25;
406 void myOverloadedSlot(const QStringList &arg) {
407 m_qtFunctionInvoked = 42;
410 void myOverloadedSlot(double arg) {
411 m_qtFunctionInvoked = 26;
414 void myOverloadedSlot(float arg) {
415 m_qtFunctionInvoked = 27;
418 void myOverloadedSlot(int arg) {
419 m_qtFunctionInvoked = 28;
422 void myOverloadedSlot(const QString &arg) {
423 m_qtFunctionInvoked = 29;
426 void myOverloadedSlot(const QColor &arg) {
427 m_qtFunctionInvoked = 30;
430 void myOverloadedSlot(const QBrush &arg) {
431 m_qtFunctionInvoked = 31;
434 void myOverloadedSlot(const QDateTime &arg) {
435 m_qtFunctionInvoked = 32;
438 void myOverloadedSlot(const QDate &arg) {
439 m_qtFunctionInvoked = 33;
442 void myOverloadedSlot(const QRegExp &arg) {
443 m_qtFunctionInvoked = 34;
446 void myOverloadedSlot(const QVariant &arg) {
447 m_qtFunctionInvoked = 35;
451 void qscript_call(int arg) {
452 m_qtFunctionInvoked = 40;
457 void myProtectedSlot() {
458 m_qtFunctionInvoked = 36;
462 void myPrivateSlot() { }
466 void mySignalWithIntArg(int arg);
467 void mySignalWithDoubleArg(double arg);
468 void mySignal2(bool arg = false);
469 void mySignalWithDateTimeArg(QDateTime dt);
470 void mySignalWithRegexArg(QRegExp r);
474 QVariant m_variantValue;
475 QVariantList m_variantListValue;
476 QString m_stringValue;
477 QStringList m_stringListValue;
478 QByteArray m_byteArrayValue;
480 double m_hiddenValue;
481 int m_writeOnlyValue;
483 QKeySequence m_shortcut;
484 CustomType m_customType;
485 int m_qtFunctionInvoked;
486 QVariantList m_actuals;
489 class MyOtherQObject : public MyQObject
492 MyOtherQObject(QObject* parent = 0)
493 : MyQObject(parent) { }
496 class MyEnumTestQObject : public QObject
499 Q_PROPERTY(QString p1 READ p1)
500 Q_PROPERTY(QString p2 READ p2)
501 Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
502 Q_PROPERTY(QString p4 READ p4)
503 Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
504 Q_PROPERTY(QString p6 READ p6)
506 MyEnumTestQObject(QObject* parent = 0)
507 : QObject(parent) { }
509 return QLatin1String("p1");
512 return QLatin1String("p2");
515 return QLatin1String("p3");
518 return QLatin1String("p4");
521 return QLatin1String("p5");
524 return QLatin1String("p5");
528 void myOtherSlot() { }
533 class tst_QWebFrame : public QObject
539 virtual ~tst_QWebFrame();
546 void getSetStaticProperty();
547 void getSetDynamicProperty();
548 void getSetChildren();
549 void callQtInvokable();
550 void connectAndDisconnect();
552 void classConstructor();
553 void overrideInvokable();
554 void transferInvokable();
557 void overloadedSlots();
558 void enumerate_data();
560 void objectDeleted();
561 void typeConversion();
563 void progressSignal();
567 QString evalJS(const QString&s) {
568 // Convert an undefined return variant to the string "undefined"
569 QVariant ret = evalJSV(s);
570 if (ret.userType() == QMetaType::Void)
573 return ret.toString();
575 QVariant evalJSV(const QString &s) {
576 return m_page->mainFrame()->evaluateJavaScript(s);
579 QString evalJS(const QString&s, QString& type) {
580 return evalJSV(s, type).toString();
582 QVariant evalJSV(const QString &s, QString& type) {
583 // As a special measure, if we get an exception we set the type to 'error'
584 // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
585 // Similarly, an array is an object, but we'd prefer to have a type of 'array'
586 // Also, consider a QMetaType::Void QVariant to be undefined
588 escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
589 evalJS("var retvalue;\
592 retvalue = eval('" + escaped + "'); \
593 typevalue = typeof retvalue; \
594 if (retvalue instanceof Array) \
595 typevalue = 'array'; \
598 retvalue = e.name + ': ' + e.message;\
599 typevalue = 'error';\
601 QVariant ret = evalJSV("retvalue");
602 if (ret.userType() != QMetaType::Void)
603 type = evalJS("typevalue");
605 ret = QString("undefined");
608 evalJS("delete retvalue; delete typevalue");
613 const QString sFalse;
614 const QString sUndefined;
615 const QString sArray;
616 const QString sFunction;
617 const QString sError;
618 const QString sString;
619 const QString sObject;
620 const QString sNumber;
625 MyQObject* m_myObject;
628 tst_QWebFrame::tst_QWebFrame()
629 : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"),
630 sString("string"), sObject("object"), sNumber("number")
634 tst_QWebFrame::~tst_QWebFrame()
638 void tst_QWebFrame::init()
640 m_view = new QWebView();
641 m_page = m_view->page();
642 m_myObject = new MyQObject();
643 m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
646 void tst_QWebFrame::cleanup()
652 void tst_QWebFrame::getSetStaticProperty()
654 QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
656 // initial value (set in MyQObject constructor)
659 QVariant ret = evalJSV("myObject.intProperty", type);
660 QCOMPARE(type, sNumber);
661 QCOMPARE(ret.type(), QVariant::Double);
662 QCOMPARE(ret.toInt(), 123);
664 QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
668 QVariant ret = evalJSV("myObject.variantProperty", type);
669 QCOMPARE(type, sString);
670 QCOMPARE(ret.type(), QVariant::String);
671 QCOMPARE(ret.toString(), QLatin1String("foo"));
673 QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
677 QVariant ret = evalJSV("myObject.stringProperty", type);
678 QCOMPARE(type, sString);
679 QCOMPARE(ret.type(), QVariant::String);
680 QCOMPARE(ret.toString(), QLatin1String("bar"));
682 QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
686 QVariant ret = evalJSV("myObject.variantListProperty", type);
687 QCOMPARE(type, sArray);
688 QCOMPARE(ret.type(), QVariant::List);
689 QVariantList vl = ret.value<QVariantList>();
690 QCOMPARE(vl.size(), 2);
691 QCOMPARE(vl.at(0).toInt(), 123);
692 QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
694 QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
695 QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
696 QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
700 QVariant ret = evalJSV("myObject.stringListProperty", type);
701 QCOMPARE(type, sArray);
702 QCOMPARE(ret.type(), QVariant::List);
703 QVariantList vl = ret.value<QVariantList>();
704 QCOMPARE(vl.size(), 2);
705 QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
706 QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
708 QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
709 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
710 QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
711 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
712 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
714 // property change in C++ should be reflected in script
715 m_myObject->setIntProperty(456);
716 QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
717 m_myObject->setIntProperty(789);
718 QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
720 m_myObject->setVariantProperty(QLatin1String("bar"));
721 QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
722 m_myObject->setVariantProperty(42);
723 QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
724 m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
726 // QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant);
728 m_myObject->setStringProperty(QLatin1String("baz"));
729 QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
730 m_myObject->setStringProperty(QLatin1String("zab"));
731 QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
733 // property change in script should be reflected in C++
734 QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
735 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
736 QCOMPARE(m_myObject->intProperty(), 123);
737 QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
738 "myObject.intProperty == 0"), sTrue);
739 QCOMPARE(m_myObject->intProperty(), 0);
740 QCOMPARE(evalJS("myObject.intProperty = '123';"
741 "myObject.intProperty == 123"), sTrue);
742 QCOMPARE(m_myObject->intProperty(), 123);
744 QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
745 QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
746 QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
747 QCOMPARE(evalJS("myObject.stringProperty = 123;"
748 "myObject.stringProperty"), QLatin1String("123"));
749 QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
751 QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
752 "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
753 QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
754 QCOMPARE(evalJS("myObject.variantProperty = 42;"
755 "myObject.variantProperty").toDouble(), 42.0);
756 QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
759 QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
760 "myObject.variantListProperty.length == 3"), sTrue);
761 QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
762 QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
763 QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
765 QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
766 "myObject.stringListProperty.length == 3"), sTrue);
767 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
768 QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
769 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
770 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
771 QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
772 QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
775 QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
776 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
778 QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
779 QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
781 // non-scriptable property
782 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
783 QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
784 QEXPECT_FAIL("", "undefined properties not supported", Continue);
785 QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
786 "myObject.hiddenProperty == 123"), sTrue);
787 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
789 // write-only property
790 QCOMPARE(m_myObject->writeOnlyProperty(), 789);
791 QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
792 QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
793 "typeof myObject.writeOnlyProperty"), sUndefined);
794 QCOMPARE(m_myObject->writeOnlyProperty(), 123);
796 // read-only property
797 QCOMPARE(m_myObject->readOnlyProperty(), 987);
798 QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
799 QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
800 "myObject.readOnlyProperty == 987"), sTrue);
801 QCOMPARE(m_myObject->readOnlyProperty(), 987);
804 void tst_QWebFrame::getSetDynamicProperty()
806 // initially the object does not have the property
807 // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
809 //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
810 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
812 // add a dynamic property in C++
813 QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
814 //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
815 QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
816 QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
818 // property change in script should be reflected in C++
819 QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
820 "myObject.dynamicProperty"), QLatin1String("foo"));
821 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
823 // delete the property (XFAIL - can't delete properties)
824 QEXPECT_FAIL("", "can't delete properties", Continue);
825 QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
827 QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
828 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
829 // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
830 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
834 void tst_QWebFrame::getSetChildren()
836 // initially the object does not have the child
837 // (again, no hasOwnProperty)
839 //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
840 QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
843 MyQObject* child = new MyQObject(m_myObject);
844 child->setObjectName("child");
845 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
846 QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
849 MyQObject* grandChild = new MyQObject(child);
850 grandChild->setObjectName("grandChild");
851 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
852 QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
856 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
857 QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
861 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
862 QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
865 Q_DECLARE_METATYPE(QVector<int>)
866 Q_DECLARE_METATYPE(QVector<double>)
867 Q_DECLARE_METATYPE(QVector<QString>)
869 void tst_QWebFrame::callQtInvokable()
871 qRegisterMetaType<QObjectList>();
873 m_myObject->resetQtFunctionInvoked();
874 QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
875 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
876 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
878 // extra arguments should silently be ignored
879 m_myObject->resetQtFunctionInvoked();
880 QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
881 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
882 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
884 m_myObject->resetQtFunctionInvoked();
885 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
886 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
887 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
888 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
890 m_myObject->resetQtFunctionInvoked();
891 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
892 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
893 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
894 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
896 m_myObject->resetQtFunctionInvoked();
897 QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
898 QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
899 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
900 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
902 m_myObject->resetQtFunctionInvoked();
903 QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
904 QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
905 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
906 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
908 m_myObject->resetQtFunctionInvoked();
909 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
910 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
911 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
912 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
914 m_myObject->resetQtFunctionInvoked();
915 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
916 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
917 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
918 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
920 m_myObject->resetQtFunctionInvoked();
921 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
922 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
923 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
924 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
926 m_myObject->resetQtFunctionInvoked();
927 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
928 QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
929 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
930 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
931 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
933 m_myObject->resetQtFunctionInvoked();
934 QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
935 QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
936 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
938 m_myObject->resetQtFunctionInvoked();
939 QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
940 QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
941 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
943 m_myObject->resetQtFunctionInvoked();
944 QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
945 QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
946 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
948 m_myObject->resetQtFunctionInvoked();
949 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
950 QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
951 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
952 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
953 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
955 m_myObject->resetQtFunctionInvoked();
956 QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
957 QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
958 m_myObject->resetQtFunctionInvoked();
961 QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
962 QCOMPARE(type, sError);
963 QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)"));
964 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
967 m_myObject->resetQtFunctionInvoked();
970 QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
971 QCOMPARE(type, sError);
972 QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
975 m_myObject->resetQtFunctionInvoked();
978 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
979 QCOMPARE(type, sUndefined);
980 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
981 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
982 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
983 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
986 m_myObject->resetQtFunctionInvoked();
989 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
990 QCOMPARE(type, sUndefined);
991 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
992 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
993 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
994 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
997 // calling function that returns (const)ref
998 m_myObject->resetQtFunctionInvoked();
1001 QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
1002 QCOMPARE(ret, sUndefined);
1003 //QVERIFY(!m_engine->hasUncaughtException());
1004 QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
1007 m_myObject->resetQtFunctionInvoked();
1010 QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
1011 QCOMPARE(ret, sUndefined);
1012 //QVERIFY(!m_engine->hasUncaughtException());
1013 QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
1016 m_myObject->resetQtFunctionInvoked();
1019 QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
1020 QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
1021 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1022 QCOMPARE(type, sFunction);
1023 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1026 m_myObject->resetQtFunctionInvoked();
1029 QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
1030 QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
1031 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1032 QCOMPARE(type, sArray);
1033 QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
1034 QVariantList vl = qvariant_cast<QVariantList>(ret);
1035 QCOMPARE(vl.count(), 1);
1038 m_myObject->resetQtFunctionInvoked();
1041 m_myObject->setVariantProperty(QVariant(123));
1042 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
1043 QCOMPARE(type, sNumber);
1044 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1045 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1046 QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
1047 QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
1048 QCOMPARE(ret.toInt(),123);
1051 /* XFAIL - variant support
1052 m_myObject->resetQtFunctionInvoked();
1054 m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
1055 QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1056 QVERIFY(ret.isVariant());
1057 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1058 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1059 QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
1060 QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
1064 m_myObject->resetQtFunctionInvoked();
1067 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
1068 QCOMPARE(type, sNumber);
1069 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1070 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1071 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
1072 QCOMPARE(ret.userType(), int(QMetaType::Double));
1073 QCOMPARE(ret.toInt(),123);
1076 m_myObject->resetQtFunctionInvoked();
1079 QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
1080 QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
1081 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1083 QVariant v = m_myObject->qtFunctionActuals().at(0);
1084 QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
1086 QVariantMap vmap = qvariant_cast<QVariantMap>(v);
1087 QCOMPARE(vmap.keys().size(), 2);
1088 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1089 QCOMPARE(vmap.value("a"), QVariant(123));
1090 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1091 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1093 QCOMPARE(type, sObject);
1095 QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
1096 vmap = qvariant_cast<QVariantMap>(ret);
1097 QCOMPARE(vmap.keys().size(), 2);
1098 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1099 QCOMPARE(vmap.value("a"), QVariant(123));
1100 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1101 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1104 m_myObject->resetQtFunctionInvoked();
1107 QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
1108 QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
1109 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1110 QVariant v = m_myObject->qtFunctionActuals().at(0);
1111 QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
1112 QList<int> ilst = qvariant_cast<QList<int> >(v);
1113 QCOMPARE(ilst.size(), 2);
1114 QCOMPARE(ilst.at(0), 1);
1115 QCOMPARE(ilst.at(1), 5);
1117 QCOMPARE(type, sArray);
1118 QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
1119 QVariantList vlst = qvariant_cast<QVariantList>(ret);
1120 QCOMPARE(vlst.size(), 2);
1121 QCOMPARE(vlst.at(0).toInt(), 1);
1122 QCOMPARE(vlst.at(1).toInt(), 5);
1125 m_myObject->resetQtFunctionInvoked();
1128 QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
1129 QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
1130 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1131 QVariant v = m_myObject->qtFunctionActuals().at(0);
1132 QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
1133 QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
1135 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1136 QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
1138 QCOMPARE(type, sFunction); // implements call, so Function, not object
1141 m_myObject->resetQtFunctionInvoked();
1143 // no implicit conversion from integer to QObject*
1145 evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
1146 QCOMPARE(type, sError);
1150 m_myObject->resetQtFunctionInvoked();
1152 QString fun = evalJS("myObject.myInvokableWithQBrushArg");
1153 Q_ASSERT(fun.isFunction());
1154 QColor color(10, 20, 30, 40);
1155 // QColor should be converted to a QBrush
1156 QVariant ret = fun.call(QString(), QStringList()
1157 << qScriptValueFromValue(m_engine, color));
1158 QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
1159 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1160 QVariant v = m_myObject->qtFunctionActuals().at(0);
1161 QCOMPARE(v.userType(), int(QMetaType::QBrush));
1162 QCOMPARE(qvariant_cast<QColor>(v), color);
1164 QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
1168 // private slots should not be part of the QObject binding
1169 QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
1171 // protected slots should be fine
1172 m_myObject->resetQtFunctionInvoked();
1173 evalJS("myObject.myProtectedSlot()");
1174 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1176 // call with too few arguments
1179 QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
1180 QCOMPARE(type, sError);
1181 QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
1184 // call function where not all types have been registered
1185 m_myObject->resetQtFunctionInvoked();
1188 QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
1189 QCOMPARE(type, sError);
1190 QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
1191 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1194 // call function with incompatible argument type
1195 m_myObject->resetQtFunctionInvoked();
1198 QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
1199 QCOMPARE(type, sError);
1200 QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
1201 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1206 m_myObject->resetQtFunctionInvoked();
1208 evalJS("new myObject(123)", type);
1209 QCOMPARE(type, sObject);
1210 QCOMPARE(m_myObject->qtFunctionInvoked(), 40);
1211 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1212 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1215 m_myObject->resetQtFunctionInvoked();
1217 evalJS("myObject(123)", type);
1218 QCOMPARE(type, sUndefined);
1219 QCOMPARE(m_myObject->qtFunctionInvoked(), 40);
1220 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1221 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1225 void tst_QWebFrame::connectAndDisconnect()
1227 // connect(function)
1228 QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
1229 QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
1230 QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
1234 evalJS("myObject.mySignal.connect(123)", type);
1235 QCOMPARE(type, sError);
1238 evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }");
1240 QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
1242 evalJS("gotSignal = false");
1243 evalJS("myObject.mySignal()");
1244 QCOMPARE(evalJS("gotSignal"), sTrue);
1245 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1246 QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1247 QCOMPARE(evalJS("slotThisObject == window"), sTrue);
1249 evalJS("gotSignal = false");
1250 m_myObject->emitMySignal();
1251 QCOMPARE(evalJS("gotSignal"), sTrue);
1252 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1254 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
1256 evalJS("gotSignal = false");
1257 m_myObject->emitMySignalWithIntArg(123);
1258 QCOMPARE(evalJS("gotSignal"), sTrue);
1259 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1260 QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
1262 QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
1265 evalJS("myObject.mySignal.disconnect(myHandler)", type);
1266 QCOMPARE(type, sError);
1269 evalJS("gotSignal = false");
1270 QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
1271 m_myObject->emitMySignal2(true);
1272 QCOMPARE(evalJS("gotSignal"), sTrue);
1273 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1274 QCOMPARE(evalJS("signalArgs[0]"), sTrue);
1276 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
1278 QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
1279 QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
1280 QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
1282 QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
1284 evalJS("gotSignal = false");
1285 m_myObject->emitMySignal2();
1286 QCOMPARE(evalJS("gotSignal"), sTrue);
1288 QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
1290 // connect(object, function)
1291 evalJS("otherObject = { name:'foo' }");
1292 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1293 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1294 evalJS("gotSignal = false");
1295 m_myObject->emitMySignal();
1296 QCOMPARE(evalJS("gotSignal"), sFalse);
1300 evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
1301 QCOMPARE(type, sError);
1304 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1305 evalJS("gotSignal = false");
1306 m_myObject->emitMySignal();
1307 QCOMPARE(evalJS("gotSignal"), sTrue);
1308 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1309 QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject"));
1310 QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1311 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
1312 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1314 evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
1315 QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
1316 evalJS("gotSignal = false");
1317 m_myObject->emitMySignal2(true);
1318 QCOMPARE(evalJS("gotSignal"), sTrue);
1319 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1320 QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
1321 QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1322 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
1323 QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
1325 QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
1326 evalJS("gotSignal = false");
1327 m_myObject->emitMySignal2(true);
1328 QCOMPARE(evalJS("gotSignal"), sTrue);
1329 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1330 QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
1331 QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1332 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
1334 // connect(obj, string)
1335 QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
1336 QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
1337 QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
1338 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
1340 // check that emitting signals from script works
1343 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1344 m_myObject->resetQtFunctionInvoked();
1345 QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
1346 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1347 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
1350 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
1351 m_myObject->resetQtFunctionInvoked();
1352 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1353 QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
1354 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1355 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1356 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
1358 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
1359 m_myObject->resetQtFunctionInvoked();
1360 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1361 QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
1362 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1363 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
1364 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
1366 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
1367 m_myObject->resetQtFunctionInvoked();
1368 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1369 QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
1370 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1371 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1372 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
1374 // connecting to overloaded slot
1375 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
1376 m_myObject->resetQtFunctionInvoked();
1377 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1378 QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
1379 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1380 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1381 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
1383 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1384 m_myObject->resetQtFunctionInvoked();
1385 QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
1386 QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
1387 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1388 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1389 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1393 // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
1395 QString ret = evalJS("(function() { }).connect()", type);
1396 QCOMPARE(type, sError);
1397 QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression (function ()\n{\n}).connect) is not object."));
1401 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type);
1402 QCOMPARE(type, sError);
1403 QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression o.connect) is not object."));
1408 QString ret = evalJS("(function() { }).connect(123)", type);
1409 QCOMPARE(type, sError);
1410 QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression (function ()\n{\n}).connect) is not object."));
1414 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type);
1415 QCOMPARE(type, sError);
1416 QCOMPARE(ret, QLatin1String("TypeError: Value undefined (result of expression o.connect) is not object."));
1421 QString ret = evalJS("myObject.myInvokable.connect(123)", type);
1422 QCOMPARE(type, sError);
1423 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1427 QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
1428 QCOMPARE(type, sError);
1429 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1434 QString ret = evalJS("myObject.mySignal.connect(123)", type);
1435 QCOMPARE(type, sError);
1436 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
1441 QString ret = evalJS("myObject.mySignal.disconnect()", type);
1442 QCOMPARE(type, sError);
1443 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1447 QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type);
1448 QCOMPARE(type, sError);
1449 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1452 /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
1455 QString ret = evalJS("(function() { }).disconnect(123)", type);
1456 QCOMPARE(type, sError);
1457 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
1463 QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
1464 QCOMPARE(type, sError);
1465 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1470 QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
1471 QCOMPARE(type, sError);
1472 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1476 QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
1477 QCOMPARE(type, sError);
1478 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1483 QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
1484 QCOMPARE(type, sError);
1485 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
1490 QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
1491 QCOMPARE(type, sError);
1492 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
1495 // when the wrapper dies, the connection stays alive
1496 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1497 m_myObject->resetQtFunctionInvoked();
1498 m_myObject->emitMySignal();
1499 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1500 evalJS("myObject = null");
1502 m_myObject->resetQtFunctionInvoked();
1503 m_myObject->emitMySignal();
1504 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1507 void tst_QWebFrame::classEnums()
1509 // We don't do the meta thing currently, unfortunately!!!
1511 QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
1512 m_engine->globalObject().setProperty("MyQObject", myClass);
1514 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()),
1515 MyQObject::FooPolicy);
1516 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()),
1517 MyQObject::BarPolicy);
1518 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()),
1519 MyQObject::BazPolicy);
1521 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()),
1522 MyQObject::FooStrategy);
1523 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()),
1524 MyQObject::BarStrategy);
1525 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()),
1526 MyQObject::BazStrategy);
1528 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()),
1529 MyQObject::NoAbility);
1530 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()),
1531 MyQObject::FooAbility);
1532 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()),
1533 MyQObject::BarAbility);
1534 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()),
1535 MyQObject::BazAbility);
1536 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()),
1537 MyQObject::AllAbility);
1539 // enums from Qt are inherited through prototype
1540 QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()),
1542 QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()),
1545 QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject"));
1547 qRegisterMetaType<MyQObject::Policy>("Policy");
1549 m_myObject->resetQtFunctionInvoked();
1550 QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined);
1551 QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
1552 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1553 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1555 m_myObject->resetQtFunctionInvoked();
1556 QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined);
1557 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1558 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1559 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1561 m_myObject->resetQtFunctionInvoked();
1563 QVariant ret = evalJS("myObject.myInvokableReturningEnum()");
1564 QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
1565 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1566 QCOMPARE(ret.isVariant());
1568 m_myObject->resetQtFunctionInvoked();
1570 QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()");
1571 QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
1572 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1573 QCOMPARE(ret.isNumber());
1578 void tst_QWebFrame::classConstructor()
1581 QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
1582 m_engine->globalObject().setProperty("MyQObject", myClass);
1584 QString myObj = evalJS("myObj = MyQObject()");
1585 QObject* qobj = myObj.toQObject();
1587 QCOMPARE(qobj->metaObject()->className(), "MyQObject");
1588 QCOMPARE(qobj->parent(), (QObject*)0);
1590 QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
1591 m_engine->globalObject().setProperty("QObject", qobjectClass);
1593 QString otherObj = evalJS("otherObj = QObject(myObj)");
1594 QObject* qqobj = otherObj.toQObject();
1595 QVERIFY(qqobj != 0);
1596 QCOMPARE(qqobj->metaObject()->className(), "QObject");
1597 QCOMPARE(qqobj->parent(), qobj);
1603 void tst_QWebFrame::overrideInvokable()
1605 m_myObject->resetQtFunctionInvoked();
1606 QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
1607 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1609 /* XFAIL - can't write to functions with RuntimeObject
1610 m_myObject->resetQtFunctionInvoked();
1611 evalJS("myObject.myInvokable = function() { window.a = 123; }");
1612 evalJS("myObject.myInvokable()");
1613 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1614 QCOMPARE(evalJS("window.a").toDouble(), 123.0);
1616 evalJS("myObject.myInvokable = function() { window.a = 456; }");
1617 evalJS("myObject.myInvokable()");
1618 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1619 QCOMPARE(evalJS("window.a").toDouble(), 456.0);
1622 evalJS("delete myObject.myInvokable");
1623 evalJS("myObject.myInvokable()");
1624 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1627 m_myObject->resetQtFunctionInvoked();
1628 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1629 evalJS("myObject.myInvokable(123)");
1630 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1633 evalJS("delete myObject.myInvokable");
1634 m_myObject->resetQtFunctionInvoked();
1635 // this form (with the '()') is read-only
1636 evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
1637 evalJS("myObject.myInvokable()");
1638 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1641 void tst_QWebFrame::transferInvokable()
1643 /* XFAIL - can't put to functions with RuntimeObject
1644 m_myObject->resetQtFunctionInvoked();
1645 evalJS("myObject.foozball = myObject.myInvokable");
1646 evalJS("myObject.foozball()");
1647 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1648 m_myObject->resetQtFunctionInvoked();
1649 evalJS("myObject.foozball = myObject.myInvokableWithIntArg");
1650 evalJS("myObject.foozball(123)");
1651 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1652 m_myObject->resetQtFunctionInvoked();
1653 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1654 evalJS("myObject.myInvokable(123)");
1655 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1657 MyOtherQObject other;
1658 m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other);
1659 evalJS("myOtherObject.foo = myObject.foozball");
1660 other.resetQtFunctionInvoked();
1661 evalJS("myOtherObject.foo(456)");
1662 QCOMPARE(other.qtFunctionInvoked(), 1);
1666 void tst_QWebFrame::findChild()
1669 QObject* child = new QObject(m_myObject);
1670 child->setObjectName(QLatin1String("myChildObject"));
1673 QString result = evalJS("myObject.findChild('noSuchChild')");
1674 QCOMPARE(result.isNull());
1678 QString result = evalJS("myObject.findChild('myChildObject')");
1679 QCOMPARE(result.isQObject());
1680 QCOMPARE(result.toQObject(), child);
1687 void tst_QWebFrame::findChildren()
1690 QObject* child = new QObject(m_myObject);
1691 child->setObjectName(QLatin1String("myChildObject"));
1694 QString result = evalJS("myObject.findChildren('noSuchChild')");
1695 QCOMPARE(result.isArray());
1696 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0);
1700 QString result = evalJS("myObject.findChildren('myChildObject')");
1701 QCOMPARE(result.isArray());
1702 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1703 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1706 QObject* namelessChild = new QObject(m_myObject);
1709 QString result = evalJS("myObject.findChildren('myChildObject')");
1710 QCOMPARE(result.isArray());
1711 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1712 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1715 QObject* anotherChild = new QObject(m_myObject);
1716 anotherChild->setObjectName(QLatin1String("anotherChildObject"));
1719 QString result = evalJS("myObject.findChildren('anotherChildObject')");
1720 QCOMPARE(result.isArray());
1721 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1722 QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
1725 anotherChild->setObjectName(QLatin1String("myChildObject"));
1727 QString result = evalJS("myObject.findChildren('myChildObject')");
1728 QCOMPARE(result.isArray());
1729 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0);
1730 QObject* o1 = result.property(QLatin1String("0")).toQObject();
1731 QObject* o2 = result.property(QLatin1String("1")).toQObject();
1733 QCOMPARE(o1, anotherChild);
1734 QCOMPARE(o2, child);
1736 QCOMPARE(o1, child);
1737 QCOMPARE(o2, anotherChild);
1743 QString result = evalJS("myObject.findChildren()");
1744 QVERIFY(result.isArray());
1746 QCOMPARE(result.property("length"), QLatin1String(count);
1747 for (int i = 0; i < 3; ++i) {
1748 QObject* o = result.property(i).toQObject();
1749 if (o == namelessChild || o == child || o == anotherChild)
1752 QVERIFY(count == 0);
1755 delete anotherChild;
1756 delete namelessChild;
1761 void tst_QWebFrame::overloadedSlots()
1763 // should pick myOverloadedSlot(double)
1764 m_myObject->resetQtFunctionInvoked();
1765 evalJS("myObject.myOverloadedSlot(10)");
1766 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
1768 // should pick myOverloadedSlot(double)
1769 m_myObject->resetQtFunctionInvoked();
1770 evalJS("myObject.myOverloadedSlot(10.0)");
1771 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
1773 // should pick myOverloadedSlot(QString)
1774 m_myObject->resetQtFunctionInvoked();
1775 evalJS("myObject.myOverloadedSlot('10')");
1776 QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
1778 // should pick myOverloadedSlot(bool)
1779 m_myObject->resetQtFunctionInvoked();
1780 evalJS("myObject.myOverloadedSlot(true)");
1781 QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
1783 // should pick myOverloadedSlot(QDateTime)
1784 m_myObject->resetQtFunctionInvoked();
1785 evalJS("myObject.myOverloadedSlot(new Date())");
1786 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1788 // should pick myOverloadedSlot(QRegExp)
1789 m_myObject->resetQtFunctionInvoked();
1790 evalJS("myObject.myOverloadedSlot(new RegExp())");
1791 QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
1793 // should pick myOverloadedSlot(QVariant)
1795 m_myObject->resetQtFunctionInvoked();
1796 QString f = evalJS("myObject.myOverloadedSlot");
1797 f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
1798 QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
1800 // should pick myOverloadedSlot(QObject*)
1801 m_myObject->resetQtFunctionInvoked();
1802 evalJS("myObject.myOverloadedSlot(myObject)");
1803 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
1805 // should pick myOverloadedSlot(QObject*)
1806 m_myObject->resetQtFunctionInvoked();
1807 evalJS("myObject.myOverloadedSlot(null)");
1808 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
1810 // should pick myOverloadedSlot(QStringList)
1811 m_myObject->resetQtFunctionInvoked();
1812 evalJS("myObject.myOverloadedSlot(['hello'])");
1813 QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
1816 void tst_QWebFrame::enumerate_data()
1818 QTest::addColumn<QStringList>("expectedNames");
1820 QTest::newRow("enumerate all")
1822 // meta-object-defined properties:
1826 << "p1" << "p2" << "p4" << "p6"
1827 // dynamic properties
1828 << "dp1" << "dp2" << "dp3"
1830 << "destroyed(QObject*)" << "destroyed()"
1832 // not included because it's private:
1833 // << "_q_reregisterTimers(void*)"
1837 << "mySlot()" << "myOtherSlot()");
1840 void tst_QWebFrame::enumerate()
1842 QFETCH(QStringList, expectedNames);
1844 MyEnumTestQObject enumQObject;
1845 // give it some dynamic properties
1846 enumQObject.setProperty("dp1", "dp1");
1847 enumQObject.setProperty("dp2", "dp2");
1848 enumQObject.setProperty("dp3", "dp3");
1849 m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
1851 // enumerate in script
1853 evalJS("var enumeratedProperties = []");
1854 evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
1855 QStringList result = evalJSV("enumeratedProperties").toStringList();
1856 QCOMPARE(result.size(), expectedNames.size());
1857 for (int i = 0; i < expectedNames.size(); ++i)
1858 QCOMPARE(result.at(i), expectedNames.at(i));
1862 void tst_QWebFrame::objectDeleted()
1864 MyQObject* qobj = new MyQObject();
1865 m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
1866 evalJS("bar.objectName = 'foo';");
1867 QCOMPARE(qobj->objectName(), QLatin1String("foo"));
1868 evalJS("bar.intProperty = 123;");
1869 QCOMPARE(qobj->intProperty(), 123);
1870 qobj->resetQtFunctionInvoked();
1871 evalJS("bar.myInvokable.call(bar);");
1872 QCOMPARE(qobj->qtFunctionInvoked(), 0);
1874 // do this, to ensure that we cache that it implements call
1877 // now delete the object
1880 QCOMPARE(evalJS("typeof bar"), sFunction);
1882 // any attempt to access properties of the object should result in an exception
1885 QString ret = evalJS("bar.objectName", type);
1886 QCOMPARE(type, sError);
1887 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1891 QString ret = evalJS("bar.objectName = 'foo'", type);
1892 QCOMPARE(type, sError);
1893 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1898 QString ret = evalJS("bar()", type);
1899 QCOMPARE(type, sError);
1900 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1903 // myInvokable is stored in member table (since we've accessed it before deletion)
1906 evalJS("bar.myInvokable", type);
1907 QCOMPARE(type, sFunction);
1912 QString ret = evalJS("bar.myInvokable.call(bar);", type);
1913 ret = evalJS("bar.myInvokable(bar)", type);
1914 QCOMPARE(type, sError);
1915 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1917 // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
1920 QString ret = evalJS("bar.myInvokableWithIntArg", type);
1921 QCOMPARE(type, sError);
1922 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
1925 // access from script
1926 evalJS("window.o = bar;");
1929 QString ret = evalJS("o()", type);
1930 QCOMPARE(type, sError);
1931 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1935 QString ret = evalJS("o.objectName", type);
1936 QCOMPARE(type, sError);
1937 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
1941 QString ret = evalJS("o.myInvokable()", type);
1942 QCOMPARE(type, sError);
1943 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
1947 QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
1948 QCOMPARE(type, sError);
1949 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
1953 void tst_QWebFrame::typeConversion()
1955 m_myObject->resetQtFunctionInvoked();
1957 QDateTime localdt(QDate(2008,1,18), QTime(12,31,0));
1958 QDateTime utclocaldt = localdt.toUTC();
1959 QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC);
1961 // Dates in JS (default to local)
1962 evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
1963 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1964 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1965 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
1967 m_myObject->resetQtFunctionInvoked();
1968 evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
1969 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
1970 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1971 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
1973 // Pushing QDateTimes into JS
1975 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
1976 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
1977 m_myObject->emitMySignalWithDateTimeArg(localdt);
1978 QCOMPARE(evalJS("window.__date_equals"), sTrue);
1979 evalJS("delete window.__date_equals");
1980 m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
1981 QCOMPARE(evalJS("window.__date_equals"), sTrue);
1982 evalJS("delete window.__date_equals");
1983 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
1986 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
1987 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
1988 m_myObject->emitMySignalWithDateTimeArg(utcdt);
1989 QCOMPARE(evalJS("window.__date_equals"), sTrue);
1990 evalJS("delete window.__date_equals");
1991 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
1996 void tst_QWebFrame::symmetricUrl()
1998 QVERIFY(m_view->url().isEmpty());
2000 QCOMPARE(m_view->history()->count(), 0);
2002 QUrl dataUrl("data:text/html,<h1>Test");
2004 m_view->setUrl(dataUrl);
2005 QCOMPARE(m_view->url(), dataUrl);
2006 QCOMPARE(m_view->history()->count(), 0);
2008 // loading is _not_ immediate, so the text isn't set just yet.
2009 QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty());
2011 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2013 QCOMPARE(m_view->history()->count(), 1);
2014 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test"));
2016 QUrl dataUrl2("data:text/html,<h1>Test2");
2017 QUrl dataUrl3("data:text/html,<h1>Test3");
2019 m_view->setUrl(dataUrl2);
2020 m_view->setUrl(dataUrl3);
2022 QCOMPARE(m_view->url(), dataUrl3);
2024 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2026 QCOMPARE(m_view->history()->count(), 2);
2028 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3"));
2031 void tst_QWebFrame::progressSignal()
2033 QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int)));
2035 QUrl dataUrl("data:text/html,<h1>Test");
2036 m_view->setUrl(dataUrl);
2038 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2040 QVERIFY(progressSpy.size() >= 2);
2042 // WebKit defines initialProgressValue as 10%, not 0%
2043 QCOMPARE(progressSpy.first().first().toInt(), 10);
2045 // But we always end at 100%
2046 QCOMPARE(progressSpy.last().first().toInt(), 100);
2049 void tst_QWebFrame::domCycles()
2051 m_view->setHtml("<html><body>");
2052 QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
2053 QVERIFY(v.type() == QVariant::Map);
2056 void tst_QWebFrame::setHtml()
2058 QString html("<html><body><p>hello world</p></body></html>");
2059 m_view->page()->mainFrame()->setHtml(html);
2060 QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
2063 QTEST_MAIN(tst_QWebFrame)
2064 #include "tst_qwebframe.moc"