2 Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies)
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>
24 #include <qwebelement.h>
27 #include <qwebframe.h>
28 #include <qwebhistory.h>
29 #include <QAbstractItemView>
30 #include <QApplication>
34 #include <QNetworkRequest>
35 #include <QNetworkReply>
37 #include <qsslerror.h>
40 #include "../WebCoreSupport/DumpRenderTreeSupportQt.h"
45 Q_DECLARE_METATYPE(CustomType)
47 Q_DECLARE_METATYPE(QBrush*)
48 Q_DECLARE_METATYPE(QObjectList)
49 Q_DECLARE_METATYPE(QList<int>)
50 Q_DECLARE_METATYPE(Qt::BrushStyle)
51 Q_DECLARE_METATYPE(QVariantList)
52 Q_DECLARE_METATYPE(QVariantMap)
54 class MyQObject : public QObject
58 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
59 Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
60 Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
61 Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty)
62 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
63 Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
64 Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
65 Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
66 Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
67 Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
68 Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
69 Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
70 Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
71 Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty)
72 Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty)
73 Q_ENUMS(Policy Strategy)
94 AllAbility = FooAbility | BarAbility | BazAbility
97 Q_DECLARE_FLAGS(Ability, AbilityFlag)
99 MyQObject(QObject* parent = 0)
102 m_variantValue(QLatin1String("foo")),
103 m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
104 m_stringValue(QLatin1String("bar")),
105 m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
106 m_brushValue(QColor(10, 20, 30, 40)),
107 m_hiddenValue(456.0),
108 m_writeOnlyValue(789),
109 m_readOnlyValue(987),
111 m_qtFunctionInvoked(-1)
113 m_variantMapValue.insert("a", QVariant(123));
114 m_variantMapValue.insert("b", QVariant(QLatin1String("foo")));
115 m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this));
120 int intProperty() const {
123 void setIntProperty(int value) {
127 QVariant variantProperty() const {
128 return m_variantValue;
130 void setVariantProperty(const QVariant &value) {
131 m_variantValue = value;
134 QVariantList variantListProperty() const {
135 return m_variantListValue;
137 void setVariantListProperty(const QVariantList &value) {
138 m_variantListValue = value;
141 QVariantMap variantMapProperty() const {
142 return m_variantMapValue;
144 void setVariantMapProperty(const QVariantMap &value) {
145 m_variantMapValue = value;
148 QString stringProperty() const {
149 return m_stringValue;
151 void setStringProperty(const QString &value) {
152 m_stringValue = value;
155 QStringList stringListProperty() const {
156 return m_stringListValue;
158 void setStringListProperty(const QStringList &value) {
159 m_stringListValue = value;
162 QByteArray byteArrayProperty() const {
163 return m_byteArrayValue;
165 void setByteArrayProperty(const QByteArray &value) {
166 m_byteArrayValue = value;
169 QBrush brushProperty() const {
172 Q_INVOKABLE void setBrushProperty(const QBrush &value) {
173 m_brushValue = value;
176 double hiddenProperty() const {
177 return m_hiddenValue;
179 void setHiddenProperty(double value) {
180 m_hiddenValue = value;
183 int writeOnlyProperty() const {
184 return m_writeOnlyValue;
186 void setWriteOnlyProperty(int value) {
187 m_writeOnlyValue = value;
190 int readOnlyProperty() const {
191 return m_readOnlyValue;
194 QKeySequence shortcut() const {
197 void setShortcut(const QKeySequence &seq) {
201 QWebElement webElementProperty() const {
205 void setWebElementProperty(const QWebElement& element) {
206 m_webElement = element;
209 CustomType propWithCustomType() const {
212 void setPropWithCustomType(const CustomType &c) {
216 QObject* objectStarProperty() const {
220 void setObjectStarProperty(QObject* object) {
221 m_objectStar = object;
225 int qtFunctionInvoked() const {
226 return m_qtFunctionInvoked;
229 QVariantList qtFunctionActuals() const {
233 void resetQtFunctionInvoked() {
234 m_qtFunctionInvoked = -1;
238 Q_INVOKABLE void myInvokable() {
239 m_qtFunctionInvoked = 0;
241 Q_INVOKABLE void myInvokableWithIntArg(int arg) {
242 m_qtFunctionInvoked = 1;
245 Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) {
246 m_qtFunctionInvoked = 2;
249 Q_INVOKABLE void myInvokableWithFloatArg(float arg) {
250 m_qtFunctionInvoked = 3;
253 Q_INVOKABLE void myInvokableWithDoubleArg(double arg) {
254 m_qtFunctionInvoked = 4;
257 Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) {
258 m_qtFunctionInvoked = 5;
261 Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) {
262 m_qtFunctionInvoked = 6;
263 m_actuals << arg1 << arg2;
265 Q_INVOKABLE int myInvokableReturningInt() {
266 m_qtFunctionInvoked = 7;
269 Q_INVOKABLE qlonglong myInvokableReturningLongLong() {
270 m_qtFunctionInvoked = 39;
273 Q_INVOKABLE QString myInvokableReturningString() {
274 m_qtFunctionInvoked = 8;
275 return QLatin1String("ciao");
277 Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload
278 m_qtFunctionInvoked = 9;
279 m_actuals << arg1 << arg2;
281 Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) {
282 m_qtFunctionInvoked = 10;
285 Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) {
286 m_qtFunctionInvoked = 36;
289 Q_INVOKABLE Policy myInvokableReturningEnum() {
290 m_qtFunctionInvoked = 37;
293 Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() {
294 m_qtFunctionInvoked = 38;
297 Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() {
298 m_qtFunctionInvoked = 11;
299 return QVector<int>();
301 Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) {
302 m_qtFunctionInvoked = 12;
304 Q_INVOKABLE QObject* myInvokableReturningQObjectStar() {
305 m_qtFunctionInvoked = 13;
308 Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) {
309 m_qtFunctionInvoked = 14;
310 m_actuals << qVariantFromValue(lst);
313 Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) {
314 m_qtFunctionInvoked = 15;
318 Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) {
319 m_qtFunctionInvoked = 16;
323 Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) {
324 m_qtFunctionInvoked = 17;
325 m_actuals << qVariantFromValue(lst);
328 Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) {
329 m_qtFunctionInvoked = 18;
330 m_actuals << qVariantFromValue(obj);
333 Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) {
334 m_qtFunctionInvoked = 19;
335 m_actuals << qVariantFromValue(brush);
338 Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) {
339 m_qtFunctionInvoked = 43;
340 m_actuals << qVariantFromValue(style);
342 Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) {
343 m_qtFunctionInvoked = 44;
344 m_actuals << qVariantFromValue(arg);
346 Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) {
347 m_qtFunctionInvoked = 45;
348 m_actuals << qVariantFromValue(arg);
350 Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) {
351 m_qtFunctionInvoked = 46;
352 m_actuals << qVariantFromValue(arg);
354 Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") {
355 m_qtFunctionInvoked = 47;
356 m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2);
358 Q_INVOKABLE QObject& myInvokableReturningRef() {
359 m_qtFunctionInvoked = 48;
362 Q_INVOKABLE const QObject& myInvokableReturningConstRef() const {
363 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
366 Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
367 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
368 m_actuals << qVariantFromValue(arg);
370 Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
371 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
372 m_actuals << qVariantFromValue(arg);
374 Q_INVOKABLE void myInvokableWithBoolArg(bool arg) {
375 m_qtFunctionInvoked = 52;
379 void emitMySignal() {
382 void emitMySignalWithIntArg(int arg) {
383 emit mySignalWithIntArg(arg);
385 void emitMySignal2(bool arg) {
388 void emitMySignal2() {
391 void emitMySignalWithDateTimeArg(QDateTime dt) {
392 emit mySignalWithDateTimeArg(dt);
394 void emitMySignalWithRegexArg(QRegExp r) {
395 emit mySignalWithRegexArg(r);
400 m_qtFunctionInvoked = 20;
402 void mySlotWithIntArg(int arg) {
403 m_qtFunctionInvoked = 21;
406 void mySlotWithDoubleArg(double arg) {
407 m_qtFunctionInvoked = 22;
410 void mySlotWithStringArg(const QString &arg) {
411 m_qtFunctionInvoked = 23;
415 void myOverloadedSlot() {
416 m_qtFunctionInvoked = 24;
418 void myOverloadedSlot(QObject* arg) {
419 m_qtFunctionInvoked = 41;
420 m_actuals << qVariantFromValue(arg);
422 void myOverloadedSlot(bool arg) {
423 m_qtFunctionInvoked = 25;
426 void myOverloadedSlot(const QStringList &arg) {
427 m_qtFunctionInvoked = 42;
430 void myOverloadedSlot(double arg) {
431 m_qtFunctionInvoked = 26;
434 void myOverloadedSlot(float arg) {
435 m_qtFunctionInvoked = 27;
438 void myOverloadedSlot(int arg) {
439 m_qtFunctionInvoked = 28;
442 void myOverloadedSlot(const QString &arg) {
443 m_qtFunctionInvoked = 29;
446 void myOverloadedSlot(const QColor &arg) {
447 m_qtFunctionInvoked = 30;
450 void myOverloadedSlot(const QBrush &arg) {
451 m_qtFunctionInvoked = 31;
454 void myOverloadedSlot(const QDateTime &arg) {
455 m_qtFunctionInvoked = 32;
458 void myOverloadedSlot(const QDate &arg) {
459 m_qtFunctionInvoked = 33;
462 void myOverloadedSlot(const QRegExp &arg) {
463 m_qtFunctionInvoked = 34;
466 void myOverloadedSlot(const QVariant &arg) {
467 m_qtFunctionInvoked = 35;
470 void myOverloadedSlot(const QWebElement &arg) {
471 m_qtFunctionInvoked = 36;
472 m_actuals << QVariant::fromValue<QWebElement>(arg);
475 void qscript_call(int arg) {
476 m_qtFunctionInvoked = 40;
481 void myProtectedSlot() {
482 m_qtFunctionInvoked = 36;
486 void myPrivateSlot() { }
490 void mySignalWithIntArg(int arg);
491 void mySignalWithDoubleArg(double arg);
492 void mySignal2(bool arg = false);
493 void mySignalWithDateTimeArg(QDateTime dt);
494 void mySignalWithRegexArg(QRegExp r);
498 QVariant m_variantValue;
499 QVariantList m_variantListValue;
500 QVariantMap m_variantMapValue;
501 QString m_stringValue;
502 QStringList m_stringListValue;
503 QByteArray m_byteArrayValue;
505 double m_hiddenValue;
506 int m_writeOnlyValue;
508 QKeySequence m_shortcut;
509 QWebElement m_webElement;
510 CustomType m_customType;
511 QObject* m_objectStar;
512 int m_qtFunctionInvoked;
513 QVariantList m_actuals;
516 class MyOtherQObject : public MyQObject
519 MyOtherQObject(QObject* parent = 0)
520 : MyQObject(parent) { }
523 class MyEnumTestQObject : public QObject
526 Q_PROPERTY(QString p1 READ p1)
527 Q_PROPERTY(QString p2 READ p2)
528 Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
529 Q_PROPERTY(QString p4 READ p4)
530 Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
531 Q_PROPERTY(QString p6 READ p6)
533 MyEnumTestQObject(QObject* parent = 0)
534 : QObject(parent) { }
536 return QLatin1String("p1");
539 return QLatin1String("p2");
542 return QLatin1String("p3");
545 return QLatin1String("p4");
548 return QLatin1String("p5");
551 return QLatin1String("p5");
555 void myOtherSlot() { }
560 class tst_QWebFrame : public QObject
566 virtual ~tst_QWebFrame();
567 bool eventFilter(QObject* watched, QEvent* event);
574 void getSetDynamicProperty();
575 void getSetDynamicProperty_data();
576 void getSetChildren();
577 void getSetChildren_data();
578 void getSetStaticProperty();
579 void callQtInvokable();
580 void connectAndDisconnect();
582 void classConstructor();
583 void overrideInvokable();
584 void transferInvokable();
587 void overloadedSlots();
588 void enumerate_data();
590 void objectDeleted();
591 void typeConversion();
592 void arrayObjectEnumerable();
594 void progressSignal();
598 void javaScriptWindowObjectCleared_data();
599 void javaScriptWindowObjectCleared();
600 void javaScriptWindowObjectClearedOnEvaluate();
602 void setHtmlWithResource();
603 void setHtmlWithBaseURL();
604 void setHtmlWithJSAlert();
605 void ipv6HostEncoding();
607 #if !defined(Q_WS_MAEMO_5)
608 // as maemo 5 does not use QComboBoxes to implement the popups
609 // this test does not make sense for it.
612 void inputFieldFocus();
613 void hitTestContent();
621 void scrollPosition();
622 void scrollToAnchor();
623 void scrollbarsOff();
624 void evaluateWillCauseRepaint();
625 void qObjectWrapperWithSameIdentity();
626 void introspectQtMethods_data();
627 void introspectQtMethods();
630 QString evalJS(const QString&s) {
631 // Convert an undefined return variant to the string "undefined"
632 QVariant ret = evalJSV(s);
633 if (ret.userType() == QMetaType::Void)
636 return ret.toString();
638 QVariant evalJSV(const QString &s) {
639 return m_page->mainFrame()->evaluateJavaScript(s);
642 QString evalJS(const QString&s, QString& type) {
643 return evalJSV(s, type).toString();
645 QVariant evalJSV(const QString &s, QString& type) {
646 // As a special measure, if we get an exception we set the type to 'error'
647 // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
648 // Similarly, an array is an object, but we'd prefer to have a type of 'array'
649 // Also, consider a QMetaType::Void QVariant to be undefined
651 escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
652 evalJS("var retvalue;\
655 retvalue = eval('" + escaped + "'); \
656 typevalue = typeof retvalue; \
657 if (retvalue instanceof Array) \
658 typevalue = 'array'; \
661 retvalue = e.name + ': ' + e.message;\
662 typevalue = 'error';\
664 QVariant ret = evalJSV("retvalue");
665 if (ret.userType() != QMetaType::Void)
666 type = evalJS("typevalue");
668 ret = QString("undefined");
671 evalJS("delete retvalue; delete typevalue");
674 void garbageCollectJS()
676 DumpRenderTreeSupportQt::garbageCollectorCollect();
678 QObject* firstChildByClassName(QObject* parent, const char* className) {
679 const QObjectList & children = parent->children();
680 foreach (QObject* child, children) {
681 if (!strcmp(child->metaObject()->className(), className)) {
689 const QString sFalse;
690 const QString sUndefined;
691 const QString sArray;
692 const QString sFunction;
693 const QString sError;
694 const QString sString;
695 const QString sObject;
696 const QString sNumber;
701 MyQObject* m_myObject;
702 QWebView* m_inputFieldsTestView;
703 int m_inputFieldTestPaintCount;
706 tst_QWebFrame::tst_QWebFrame()
707 : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"),
708 sString("string"), sObject("object"), sNumber("number"), m_inputFieldsTestView(0), m_inputFieldTestPaintCount(0)
712 tst_QWebFrame::~tst_QWebFrame()
716 bool tst_QWebFrame::eventFilter(QObject* watched, QEvent* event)
718 // used on the inputFieldFocus test
719 if (watched == m_inputFieldsTestView) {
720 if (event->type() == QEvent::Paint)
721 m_inputFieldTestPaintCount++;
723 return QObject::eventFilter(watched, event);
726 void tst_QWebFrame::init()
728 m_view = new QWebView();
729 m_page = m_view->page();
730 m_myObject = new MyQObject();
731 m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
734 void tst_QWebFrame::cleanup()
740 void tst_QWebFrame::getSetStaticProperty()
742 m_page->mainFrame()->setHtml("<html><head><body></body></html>");
743 QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
745 // initial value (set in MyQObject constructor)
748 QVariant ret = evalJSV("myObject.intProperty", type);
749 QCOMPARE(type, sNumber);
750 QCOMPARE(ret.type(), QVariant::Double);
751 QCOMPARE(ret.toInt(), 123);
753 QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
757 QVariant ret = evalJSV("myObject.variantProperty", type);
758 QCOMPARE(type, sString);
759 QCOMPARE(ret.type(), QVariant::String);
760 QCOMPARE(ret.toString(), QLatin1String("foo"));
762 QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
766 QVariant ret = evalJSV("myObject.stringProperty", type);
767 QCOMPARE(type, sString);
768 QCOMPARE(ret.type(), QVariant::String);
769 QCOMPARE(ret.toString(), QLatin1String("bar"));
771 QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
775 QVariant ret = evalJSV("myObject.variantListProperty", type);
776 QCOMPARE(type, sArray);
777 QCOMPARE(ret.type(), QVariant::List);
778 QVariantList vl = ret.value<QVariantList>();
779 QCOMPARE(vl.size(), 2);
780 QCOMPARE(vl.at(0).toInt(), 123);
781 QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
783 QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
784 QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
785 QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
789 QVariant ret = evalJSV("myObject.variantMapProperty", type);
790 QCOMPARE(type, sObject);
791 QCOMPARE(ret.type(), QVariant::Map);
792 QVariantMap vm = ret.value<QVariantMap>();
793 QCOMPARE(vm.size(), 3);
794 QCOMPARE(vm.value("a").toInt(), 123);
795 QCOMPARE(vm.value("b").toString(), QLatin1String("foo"));
796 QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject));
798 QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue);
799 QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue);
800 QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue);
804 QVariant ret = evalJSV("myObject.stringListProperty", type);
805 QCOMPARE(type, sArray);
806 QCOMPARE(ret.type(), QVariant::List);
807 QVariantList vl = ret.value<QVariantList>();
808 QCOMPARE(vl.size(), 2);
809 QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
810 QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
812 QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
813 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
814 QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
815 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
816 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
818 // property change in C++ should be reflected in script
819 m_myObject->setIntProperty(456);
820 QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
821 m_myObject->setIntProperty(789);
822 QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
824 m_myObject->setVariantProperty(QLatin1String("bar"));
825 QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
826 m_myObject->setVariantProperty(42);
827 QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
828 m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
830 // QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant);
832 m_myObject->setStringProperty(QLatin1String("baz"));
833 QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
834 m_myObject->setStringProperty(QLatin1String("zab"));
835 QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
837 // property change in script should be reflected in C++
838 QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
839 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
840 QCOMPARE(m_myObject->intProperty(), 123);
841 QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
842 "myObject.intProperty == 0"), sTrue);
843 QCOMPARE(m_myObject->intProperty(), 0);
844 QCOMPARE(evalJS("myObject.intProperty = '123';"
845 "myObject.intProperty == 123"), sTrue);
846 QCOMPARE(m_myObject->intProperty(), 123);
848 QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
849 QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
850 QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
851 QCOMPARE(evalJS("myObject.stringProperty = 123;"
852 "myObject.stringProperty"), QLatin1String("123"));
853 QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
854 QCOMPARE(evalJS("myObject.stringProperty = null"), QString());
855 QCOMPARE(evalJS("myObject.stringProperty"), QString());
856 QCOMPARE(m_myObject->stringProperty(), QString());
857 QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined);
858 QCOMPARE(evalJS("myObject.stringProperty"), QString());
859 QCOMPARE(m_myObject->stringProperty(), QString());
861 QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);"
862 "myObject.variantProperty").toDouble(), 1234.0);
863 QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0);
865 QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);"
866 "myObject.variantProperty"), sTrue);
867 QCOMPARE(m_myObject->variantProperty().toBool(), true);
869 QCOMPARE(evalJS("myObject.variantProperty = null;"
870 "myObject.variantProperty.valueOf()"), sUndefined);
871 QCOMPARE(m_myObject->variantProperty(), QVariant());
872 QCOMPARE(evalJS("myObject.variantProperty = undefined;"
873 "myObject.variantProperty.valueOf()"), sUndefined);
874 QCOMPARE(m_myObject->variantProperty(), QVariant());
876 QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
877 "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
878 QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
879 QCOMPARE(evalJS("myObject.variantProperty = 42;"
880 "myObject.variantProperty").toDouble(), 42.0);
881 QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
883 QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
884 "myObject.variantListProperty.length == 3"), sTrue);
885 QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
886 QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
887 QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
889 QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
890 "myObject.stringListProperty.length == 3"), sTrue);
891 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
892 QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
893 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
894 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
895 QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
896 QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
897 evalJS("myObject.webElementProperty=document.body;");
898 QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY"));
901 QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
902 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
904 QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
905 QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
908 QCOMPARE(evalJS("myObject.customProperty"), sUndefined);
909 QCOMPARE(evalJS("myObject.customProperty = 123;"
910 "myObject.customProperty == 123"), sTrue);
911 QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty");
912 QCOMPARE(v.type(), QVariant::Double);
913 QCOMPARE(v.toInt(), 123);
915 // non-scriptable property
916 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
917 QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
918 QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
919 "myObject.hiddenProperty == 123"), sTrue);
920 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
922 // write-only property
923 QCOMPARE(m_myObject->writeOnlyProperty(), 789);
924 QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
925 QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
926 "typeof myObject.writeOnlyProperty"), sUndefined);
927 QCOMPARE(m_myObject->writeOnlyProperty(), 123);
929 // read-only property
930 QCOMPARE(m_myObject->readOnlyProperty(), 987);
931 QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
932 QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
933 "myObject.readOnlyProperty == 987"), sTrue);
934 QCOMPARE(m_myObject->readOnlyProperty(), 987);
937 m_myObject->setObjectStarProperty(0);
938 QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0);
939 QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue);
940 QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
941 QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse);
942 QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue);
943 QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"),
945 m_myObject->setObjectStarProperty(this);
946 QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue);
947 QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
948 QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue);
949 QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue);
952 void tst_QWebFrame::getSetDynamicProperty()
954 QFETCH(bool, garbageCollect);
956 // initially the object does not have the property
957 // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
959 //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
960 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
962 // add a dynamic property in C++
963 QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
964 //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
965 QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
966 QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
967 if( garbageCollect ) {
969 QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
972 // property change in script should be reflected in C++
973 QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
974 "myObject.dynamicProperty"), QLatin1String("foo"));
975 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
976 if( garbageCollect ) {
978 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
981 // add a dynamic property in C++ to another QObject
982 QObject* propertyObject = new QObject(m_myObject);
983 QCOMPARE(m_myObject->setProperty("dynamicObjectProperty", qVariantFromValue(propertyObject)), false);
984 QCOMPARE(evalJS("typeof myObject.dynamicObjectProperty != 'undefined'"), sTrue);
985 evalJS("myObject.dynamicObjectProperty.jsProperty = 123");
986 QCOMPARE(evalJS("myObject.dynamicObjectProperty.jsProperty == 123"), sTrue);
987 if( garbageCollect ) {
989 QCOMPARE(evalJS("typeof myObject.dynamicObjectProperty != 'undefined'"), sTrue);
990 QCOMPARE(evalJS("myObject.dynamicObjectProperty.jsProperty == 123"), sTrue);
992 QCOMPARE(m_myObject->setProperty("dynamicObjectProperty", QVariant()), false);
993 delete propertyObject;
994 QCOMPARE(evalJS("typeof myObject.dynamicObjectProperty == 'undefined'"), sTrue);
996 // delete the property (XFAIL - can't delete properties)
997 QEXPECT_FAIL("", "can't delete properties", Continue);
998 QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
1000 QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
1001 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
1002 // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
1003 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
1006 evalJS("myObject.dynamicProperty = undefined");
1009 void tst_QWebFrame::getSetDynamicProperty_data()
1011 QTest::addColumn<bool>("garbageCollect");
1012 QTest::newRow("with garbageCollect") << true;
1013 QTest::newRow("without garbageCollect") << false;
1016 void tst_QWebFrame::getSetChildren()
1018 QFETCH(bool, garbageCollect);
1020 // initially the object does not have the child
1021 // (again, no hasOwnProperty)
1023 //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
1024 QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
1027 MyQObject* child = new MyQObject(m_myObject);
1028 child->setObjectName("child");
1029 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
1030 QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
1031 evalJS("myObject.child.jsProperty = 123");
1032 QCOMPARE(evalJS("myObject.child.jsProperty == 123"), sTrue);
1034 if( garbageCollect ) {
1036 QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
1037 QCOMPARE(evalJS("myObject.child.jsProperty == 123"), sTrue);
1041 MyQObject* grandChild = new MyQObject(child);
1042 grandChild->setObjectName("grandChild");
1043 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
1044 QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
1045 evalJS("myObject.child.grandChild.jsProperty = 123");
1046 evalJS("myObject.child.grandChild.jsProperty = 123");
1047 if( garbageCollect ) {
1049 QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
1050 QCOMPARE(evalJS("myObject.child.grandChild.jsProperty == 123"), sTrue);
1053 // delete grandchild
1055 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
1056 QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
1060 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
1061 QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
1062 if( garbageCollect ) {
1064 QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
1069 void tst_QWebFrame::getSetChildren_data()
1071 QTest::addColumn<bool>("garbageCollect");
1072 QTest::newRow("with garbageCollect") << true;
1073 QTest::newRow("without garbageCollect") << false;
1076 Q_DECLARE_METATYPE(QVector<int>)
1077 Q_DECLARE_METATYPE(QVector<double>)
1078 Q_DECLARE_METATYPE(QVector<QString>)
1080 void tst_QWebFrame::callQtInvokable()
1082 qRegisterMetaType<QObjectList>();
1084 m_myObject->resetQtFunctionInvoked();
1085 QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
1086 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1087 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1089 // extra arguments should silently be ignored
1090 m_myObject->resetQtFunctionInvoked();
1091 QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
1092 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1093 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1095 m_myObject->resetQtFunctionInvoked();
1096 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
1097 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1098 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1099 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1101 m_myObject->resetQtFunctionInvoked();
1102 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
1103 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1104 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1105 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1107 m_myObject->resetQtFunctionInvoked();
1108 QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
1109 QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
1110 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1111 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
1113 m_myObject->resetQtFunctionInvoked();
1114 QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
1115 QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
1116 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1117 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1119 m_myObject->resetQtFunctionInvoked();
1120 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
1121 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1122 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1123 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1125 m_myObject->resetQtFunctionInvoked();
1126 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined);
1127 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1128 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1129 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5);
1131 m_myObject->resetQtFunctionInvoked();
1132 QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined);
1133 QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
1134 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1135 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true);
1137 m_myObject->resetQtFunctionInvoked();
1138 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
1139 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1140 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1141 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
1143 m_myObject->resetQtFunctionInvoked();
1144 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
1145 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1146 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1147 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1149 m_myObject->resetQtFunctionInvoked();
1150 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined);
1151 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1152 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1153 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1154 QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
1156 m_myObject->resetQtFunctionInvoked();
1157 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined);
1158 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1159 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1160 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1161 QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
1163 m_myObject->resetQtFunctionInvoked();
1164 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
1165 QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
1166 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1167 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1168 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1170 m_myObject->resetQtFunctionInvoked();
1171 QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
1172 QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
1173 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1175 m_myObject->resetQtFunctionInvoked();
1176 QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
1177 QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
1178 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1180 m_myObject->resetQtFunctionInvoked();
1181 QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
1182 QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
1183 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1185 m_myObject->resetQtFunctionInvoked();
1186 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
1187 QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
1188 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1189 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1190 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1192 m_myObject->resetQtFunctionInvoked();
1193 QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
1194 QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
1195 m_myObject->resetQtFunctionInvoked();
1198 QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
1199 QCOMPARE(type, sError);
1200 QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)"));
1201 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1204 m_myObject->resetQtFunctionInvoked();
1207 QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
1208 QCOMPARE(type, sError);
1209 QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
1212 m_myObject->resetQtFunctionInvoked();
1215 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
1216 QCOMPARE(type, sUndefined);
1217 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1218 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1219 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1220 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
1223 m_myObject->resetQtFunctionInvoked();
1226 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
1227 QCOMPARE(type, sUndefined);
1228 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1229 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1230 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1231 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
1234 // calling function that returns (const)ref
1235 m_myObject->resetQtFunctionInvoked();
1238 QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
1239 QCOMPARE(ret, sUndefined);
1240 //QVERIFY(!m_engine->hasUncaughtException());
1241 QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
1244 m_myObject->resetQtFunctionInvoked();
1247 QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
1248 QCOMPARE(ret, sUndefined);
1249 //QVERIFY(!m_engine->hasUncaughtException());
1250 QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
1253 m_myObject->resetQtFunctionInvoked();
1256 QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
1257 QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
1258 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1259 QCOMPARE(type, sObject);
1260 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1263 m_myObject->resetQtFunctionInvoked();
1266 QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
1267 QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
1268 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1269 QCOMPARE(type, sArray);
1270 QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
1271 QVariantList vl = qvariant_cast<QVariantList>(ret);
1272 QCOMPARE(vl.count(), 1);
1275 m_myObject->resetQtFunctionInvoked();
1278 m_myObject->setVariantProperty(QVariant(123));
1279 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
1280 QCOMPARE(type, sNumber);
1281 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1282 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1283 QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
1284 QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
1285 QCOMPARE(ret.toInt(),123);
1288 m_myObject->resetQtFunctionInvoked();
1291 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type);
1292 QCOMPARE(type, sObject);
1293 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1294 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1295 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1296 QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
1299 m_myObject->resetQtFunctionInvoked();
1302 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type);
1303 QCOMPARE(type, sObject);
1304 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1305 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1306 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1307 QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
1310 /* XFAIL - variant support
1311 m_myObject->resetQtFunctionInvoked();
1313 m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
1314 QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1315 QVERIFY(ret.isVariant());
1316 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1317 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1318 QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
1319 QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
1323 m_myObject->resetQtFunctionInvoked();
1326 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
1327 QCOMPARE(type, sNumber);
1328 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1329 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1330 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
1331 QCOMPARE(ret.userType(), int(QMetaType::Double));
1332 QCOMPARE(ret.toInt(),123);
1335 m_myObject->resetQtFunctionInvoked();
1338 QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
1339 QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
1340 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1342 QVariant v = m_myObject->qtFunctionActuals().at(0);
1343 QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
1345 QVariantMap vmap = qvariant_cast<QVariantMap>(v);
1346 QCOMPARE(vmap.keys().size(), 2);
1347 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1348 QCOMPARE(vmap.value("a"), QVariant(123));
1349 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1350 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1352 QCOMPARE(type, sObject);
1354 QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
1355 vmap = qvariant_cast<QVariantMap>(ret);
1356 QCOMPARE(vmap.keys().size(), 2);
1357 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1358 QCOMPARE(vmap.value("a"), QVariant(123));
1359 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1360 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1363 m_myObject->resetQtFunctionInvoked();
1366 QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
1367 QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
1368 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1369 QVariant v = m_myObject->qtFunctionActuals().at(0);
1370 QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
1371 QList<int> ilst = qvariant_cast<QList<int> >(v);
1372 QCOMPARE(ilst.size(), 2);
1373 QCOMPARE(ilst.at(0), 1);
1374 QCOMPARE(ilst.at(1), 5);
1376 QCOMPARE(type, sArray);
1377 QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
1378 QVariantList vlst = qvariant_cast<QVariantList>(ret);
1379 QCOMPARE(vlst.size(), 2);
1380 QCOMPARE(vlst.at(0).toInt(), 1);
1381 QCOMPARE(vlst.at(1).toInt(), 5);
1384 m_myObject->resetQtFunctionInvoked();
1387 QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
1388 QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
1389 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1390 QVariant v = m_myObject->qtFunctionActuals().at(0);
1391 QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
1392 QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
1394 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1395 QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
1397 QCOMPARE(type, sObject);
1400 m_myObject->resetQtFunctionInvoked();
1402 // no implicit conversion from integer to QObject*
1404 evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
1405 QCOMPARE(type, sError);
1409 m_myObject->resetQtFunctionInvoked();
1411 QString fun = evalJS("myObject.myInvokableWithQBrushArg");
1412 Q_ASSERT(fun.isFunction());
1413 QColor color(10, 20, 30, 40);
1414 // QColor should be converted to a QBrush
1415 QVariant ret = fun.call(QString(), QStringList()
1416 << qScriptValueFromValue(m_engine, color));
1417 QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
1418 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1419 QVariant v = m_myObject->qtFunctionActuals().at(0);
1420 QCOMPARE(v.userType(), int(QMetaType::QBrush));
1421 QCOMPARE(qvariant_cast<QColor>(v), color);
1423 QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
1427 // private slots should not be part of the QObject binding
1428 QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
1430 // protected slots should be fine
1431 m_myObject->resetQtFunctionInvoked();
1432 evalJS("myObject.myProtectedSlot()");
1433 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1435 // call with too few arguments
1438 QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
1439 QCOMPARE(type, sError);
1440 QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
1443 // call function where not all types have been registered
1444 m_myObject->resetQtFunctionInvoked();
1447 QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
1448 QCOMPARE(type, sError);
1449 QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
1450 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1453 // call function with incompatible argument type
1454 m_myObject->resetQtFunctionInvoked();
1457 QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
1458 QCOMPARE(type, sError);
1459 QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
1460 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1464 void tst_QWebFrame::connectAndDisconnect()
1466 // connect(function)
1467 QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
1468 QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
1469 QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
1473 evalJS("myObject.mySignal.connect(123)", type);
1474 QCOMPARE(type, sError);
1477 evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }");
1479 QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
1481 evalJS("gotSignal = false");
1482 evalJS("myObject.mySignal()");
1483 QCOMPARE(evalJS("gotSignal"), sTrue);
1484 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1485 QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1486 QCOMPARE(evalJS("slotThisObject == window"), sTrue);
1488 evalJS("gotSignal = false");
1489 m_myObject->emitMySignal();
1490 QCOMPARE(evalJS("gotSignal"), sTrue);
1491 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1493 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
1495 evalJS("gotSignal = false");
1496 m_myObject->emitMySignalWithIntArg(123);
1497 QCOMPARE(evalJS("gotSignal"), sTrue);
1498 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1499 QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
1501 QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
1504 evalJS("myObject.mySignal.disconnect(myHandler)", type);
1505 QCOMPARE(type, sError);
1508 evalJS("gotSignal = false");
1509 QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
1510 m_myObject->emitMySignal2(true);
1511 QCOMPARE(evalJS("gotSignal"), sTrue);
1512 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1513 QCOMPARE(evalJS("signalArgs[0]"), sTrue);
1515 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
1517 QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
1518 QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
1519 QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
1521 QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
1523 evalJS("gotSignal = false");
1524 m_myObject->emitMySignal2();
1525 QCOMPARE(evalJS("gotSignal"), sTrue);
1527 QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
1529 // connect(object, function)
1530 evalJS("otherObject = { name:'foo' }");
1531 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1532 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1533 evalJS("gotSignal = false");
1534 m_myObject->emitMySignal();
1535 QCOMPARE(evalJS("gotSignal"), sFalse);
1539 evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
1540 QCOMPARE(type, sError);
1543 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1544 evalJS("gotSignal = false");
1545 m_myObject->emitMySignal();
1546 QCOMPARE(evalJS("gotSignal"), sTrue);
1547 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1548 QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject"));
1549 QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1550 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
1551 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1553 evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
1554 QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
1555 evalJS("gotSignal = false");
1556 m_myObject->emitMySignal2(true);
1557 QCOMPARE(evalJS("gotSignal"), sTrue);
1558 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1559 QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
1560 QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1561 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
1562 QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
1564 QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
1565 evalJS("gotSignal = false");
1566 m_myObject->emitMySignal2(true);
1567 QCOMPARE(evalJS("gotSignal"), sTrue);
1568 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1569 QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
1570 QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1571 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
1573 // connect(obj, string)
1574 QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
1575 QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
1576 QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
1577 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
1579 // check that emitting signals from script works
1582 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1583 m_myObject->resetQtFunctionInvoked();
1584 QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
1585 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1586 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
1589 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
1590 m_myObject->resetQtFunctionInvoked();
1591 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1592 QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
1593 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1594 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1595 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
1597 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
1598 m_myObject->resetQtFunctionInvoked();
1599 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1600 QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
1601 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1602 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
1603 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
1605 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
1606 m_myObject->resetQtFunctionInvoked();
1607 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1608 QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
1609 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1610 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1611 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
1613 // connecting to overloaded slot
1614 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
1615 m_myObject->resetQtFunctionInvoked();
1616 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1617 QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
1618 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1619 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1620 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
1622 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1623 m_myObject->resetQtFunctionInvoked();
1624 QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
1625 QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
1626 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1627 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1628 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1632 // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
1634 QString ret = evalJS("(function() { }).connect()", type);
1635 QCOMPARE(type, sError);
1636 QCOMPARE(ret, QLatin1String("TypeError: Result of expression '(function() { }).connect' [undefined] is not a function."));
1640 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type);
1641 QCOMPARE(type, sError);
1642 QCOMPARE(ret, QLatin1String("TypeError: Result of expression 'o.connect' [undefined] is not a function."));
1647 QString ret = evalJS("(function() { }).connect(123)", type);
1648 QCOMPARE(type, sError);
1649 QCOMPARE(ret, QLatin1String("TypeError: Result of expression '(function() { }).connect' [undefined] is not a function."));
1653 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type);
1654 QCOMPARE(type, sError);
1655 QCOMPARE(ret, QLatin1String("TypeError: Result of expression 'o.connect' [undefined] is not a function."));
1660 QString ret = evalJS("myObject.myInvokable.connect(123)", type);
1661 QCOMPARE(type, sError);
1662 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1666 QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
1667 QCOMPARE(type, sError);
1668 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1673 QString ret = evalJS("myObject.mySignal.connect(123)", type);
1674 QCOMPARE(type, sError);
1675 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
1680 QString ret = evalJS("myObject.mySignal.disconnect()", type);
1681 QCOMPARE(type, sError);
1682 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1686 QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type);
1687 QCOMPARE(type, sError);
1688 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1691 /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
1694 QString ret = evalJS("(function() { }).disconnect(123)", type);
1695 QCOMPARE(type, sError);
1696 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
1702 QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
1703 QCOMPARE(type, sError);
1704 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1709 QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
1710 QCOMPARE(type, sError);
1711 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1715 QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
1716 QCOMPARE(type, sError);
1717 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1722 QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
1723 QCOMPARE(type, sError);
1724 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
1729 QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
1730 QCOMPARE(type, sError);
1731 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
1734 // when the wrapper dies, the connection stays alive
1735 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1736 m_myObject->resetQtFunctionInvoked();
1737 m_myObject->emitMySignal();
1738 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1739 evalJS("myObject = null");
1741 m_myObject->resetQtFunctionInvoked();
1742 m_myObject->emitMySignal();
1743 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1746 void tst_QWebFrame::classEnums()
1748 // We don't do the meta thing currently, unfortunately!!!
1750 QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
1751 m_engine->globalObject().setProperty("MyQObject", myClass);
1753 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()),
1754 MyQObject::FooPolicy);
1755 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()),
1756 MyQObject::BarPolicy);
1757 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()),
1758 MyQObject::BazPolicy);
1760 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()),
1761 MyQObject::FooStrategy);
1762 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()),
1763 MyQObject::BarStrategy);
1764 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()),
1765 MyQObject::BazStrategy);
1767 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()),
1768 MyQObject::NoAbility);
1769 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()),
1770 MyQObject::FooAbility);
1771 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()),
1772 MyQObject::BarAbility);
1773 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()),
1774 MyQObject::BazAbility);
1775 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()),
1776 MyQObject::AllAbility);
1778 // enums from Qt are inherited through prototype
1779 QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()),
1781 QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()),
1784 QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject"));
1786 qRegisterMetaType<MyQObject::Policy>("Policy");
1788 m_myObject->resetQtFunctionInvoked();
1789 QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined);
1790 QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
1791 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1792 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1794 m_myObject->resetQtFunctionInvoked();
1795 QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined);
1796 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1797 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1798 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1800 m_myObject->resetQtFunctionInvoked();
1802 QVariant ret = evalJS("myObject.myInvokableReturningEnum()");
1803 QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
1804 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1805 QCOMPARE(ret.isVariant());
1807 m_myObject->resetQtFunctionInvoked();
1809 QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()");
1810 QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
1811 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1812 QCOMPARE(ret.isNumber());
1817 void tst_QWebFrame::classConstructor()
1820 QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
1821 m_engine->globalObject().setProperty("MyQObject", myClass);
1823 QString myObj = evalJS("myObj = MyQObject()");
1824 QObject* qobj = myObj.toQObject();
1826 QCOMPARE(qobj->metaObject()->className(), "MyQObject");
1827 QCOMPARE(qobj->parent(), (QObject*)0);
1829 QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
1830 m_engine->globalObject().setProperty("QObject", qobjectClass);
1832 QString otherObj = evalJS("otherObj = QObject(myObj)");
1833 QObject* qqobj = otherObj.toQObject();
1834 QVERIFY(qqobj != 0);
1835 QCOMPARE(qqobj->metaObject()->className(), "QObject");
1836 QCOMPARE(qqobj->parent(), qobj);
1842 void tst_QWebFrame::overrideInvokable()
1844 m_myObject->resetQtFunctionInvoked();
1845 QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
1846 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1848 /* XFAIL - can't write to functions with RuntimeObject
1849 m_myObject->resetQtFunctionInvoked();
1850 evalJS("myObject.myInvokable = function() { window.a = 123; }");
1851 evalJS("myObject.myInvokable()");
1852 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1853 QCOMPARE(evalJS("window.a").toDouble(), 123.0);
1855 evalJS("myObject.myInvokable = function() { window.a = 456; }");
1856 evalJS("myObject.myInvokable()");
1857 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1858 QCOMPARE(evalJS("window.a").toDouble(), 456.0);
1861 evalJS("delete myObject.myInvokable");
1862 evalJS("myObject.myInvokable()");
1863 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1866 m_myObject->resetQtFunctionInvoked();
1867 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1868 evalJS("myObject.myInvokable(123)");
1869 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1872 evalJS("delete myObject.myInvokable");
1873 m_myObject->resetQtFunctionInvoked();
1874 // this form (with the '()') is read-only
1875 evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
1876 evalJS("myObject.myInvokable()");
1877 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1880 void tst_QWebFrame::transferInvokable()
1882 /* XFAIL - can't put to functions with RuntimeObject
1883 m_myObject->resetQtFunctionInvoked();
1884 evalJS("myObject.foozball = myObject.myInvokable");
1885 evalJS("myObject.foozball()");
1886 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1887 m_myObject->resetQtFunctionInvoked();
1888 evalJS("myObject.foozball = myObject.myInvokableWithIntArg");
1889 evalJS("myObject.foozball(123)");
1890 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1891 m_myObject->resetQtFunctionInvoked();
1892 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1893 evalJS("myObject.myInvokable(123)");
1894 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1896 MyOtherQObject other;
1897 m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other);
1898 evalJS("myOtherObject.foo = myObject.foozball");
1899 other.resetQtFunctionInvoked();
1900 evalJS("myOtherObject.foo(456)");
1901 QCOMPARE(other.qtFunctionInvoked(), 1);
1905 void tst_QWebFrame::findChild()
1908 QObject* child = new QObject(m_myObject);
1909 child->setObjectName(QLatin1String("myChildObject"));
1912 QString result = evalJS("myObject.findChild('noSuchChild')");
1913 QCOMPARE(result.isNull());
1917 QString result = evalJS("myObject.findChild('myChildObject')");
1918 QCOMPARE(result.isQObject());
1919 QCOMPARE(result.toQObject(), child);
1926 void tst_QWebFrame::findChildren()
1929 QObject* child = new QObject(m_myObject);
1930 child->setObjectName(QLatin1String("myChildObject"));
1933 QString result = evalJS("myObject.findChildren('noSuchChild')");
1934 QCOMPARE(result.isArray());
1935 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0);
1939 QString result = evalJS("myObject.findChildren('myChildObject')");
1940 QCOMPARE(result.isArray());
1941 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1942 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1945 QObject* namelessChild = new QObject(m_myObject);
1948 QString result = evalJS("myObject.findChildren('myChildObject')");
1949 QCOMPARE(result.isArray());
1950 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1951 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1954 QObject* anotherChild = new QObject(m_myObject);
1955 anotherChild->setObjectName(QLatin1String("anotherChildObject"));
1958 QString result = evalJS("myObject.findChildren('anotherChildObject')");
1959 QCOMPARE(result.isArray());
1960 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1961 QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
1964 anotherChild->setObjectName(QLatin1String("myChildObject"));
1966 QString result = evalJS("myObject.findChildren('myChildObject')");
1967 QCOMPARE(result.isArray());
1968 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0);
1969 QObject* o1 = result.property(QLatin1String("0")).toQObject();
1970 QObject* o2 = result.property(QLatin1String("1")).toQObject();
1972 QCOMPARE(o1, anotherChild);
1973 QCOMPARE(o2, child);
1975 QCOMPARE(o1, child);
1976 QCOMPARE(o2, anotherChild);
1982 QString result = evalJS("myObject.findChildren()");
1983 QVERIFY(result.isArray());
1985 QCOMPARE(result.property("length"), QLatin1String(count);
1986 for (int i = 0; i < 3; ++i) {
1987 QObject* o = result.property(i).toQObject();
1988 if (o == namelessChild || o == child || o == anotherChild)
1991 QVERIFY(count == 0);
1994 delete anotherChild;
1995 delete namelessChild;
2000 void tst_QWebFrame::overloadedSlots()
2002 // should pick myOverloadedSlot(double)
2003 m_myObject->resetQtFunctionInvoked();
2004 evalJS("myObject.myOverloadedSlot(10)");
2005 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
2007 // should pick myOverloadedSlot(double)
2008 m_myObject->resetQtFunctionInvoked();
2009 evalJS("myObject.myOverloadedSlot(10.0)");
2010 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
2012 // should pick myOverloadedSlot(QString)
2013 m_myObject->resetQtFunctionInvoked();
2014 evalJS("myObject.myOverloadedSlot('10')");
2015 QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
2017 // should pick myOverloadedSlot(bool)
2018 m_myObject->resetQtFunctionInvoked();
2019 evalJS("myObject.myOverloadedSlot(true)");
2020 QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
2022 // should pick myOverloadedSlot(QDateTime)
2023 m_myObject->resetQtFunctionInvoked();
2024 evalJS("myObject.myOverloadedSlot(new Date())");
2025 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2027 // should pick myOverloadedSlot(QRegExp)
2028 m_myObject->resetQtFunctionInvoked();
2029 evalJS("myObject.myOverloadedSlot(new RegExp())");
2030 QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
2032 // should pick myOverloadedSlot(QVariant)
2034 m_myObject->resetQtFunctionInvoked();
2035 QString f = evalJS("myObject.myOverloadedSlot");
2036 f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
2037 QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
2040 // should pick myOverloadedSlot(QRegExp)
2041 m_myObject->resetQtFunctionInvoked();
2042 evalJS("myObject.myOverloadedSlot(document.body)");
2043 QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=37319", Continue);
2044 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
2046 // should pick myOverloadedSlot(QObject*)
2047 m_myObject->resetQtFunctionInvoked();
2048 evalJS("myObject.myOverloadedSlot(myObject)");
2049 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
2051 // should pick myOverloadedSlot(QObject*)
2052 m_myObject->resetQtFunctionInvoked();
2053 evalJS("myObject.myOverloadedSlot(null)");
2054 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
2056 // should pick myOverloadedSlot(QStringList)
2057 m_myObject->resetQtFunctionInvoked();
2058 evalJS("myObject.myOverloadedSlot(['hello'])");
2059 QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
2062 void tst_QWebFrame::enumerate_data()
2064 QTest::addColumn<QStringList>("expectedNames");
2066 QTest::newRow("enumerate all")
2068 // meta-object-defined properties:
2072 << "p1" << "p2" << "p4" << "p6"
2073 // dynamic properties
2074 << "dp1" << "dp2" << "dp3"
2076 << "destroyed(QObject*)" << "destroyed()"
2078 // not included because it's private:
2079 // << "_q_reregisterTimers(void*)"
2083 << "mySlot()" << "myOtherSlot()");
2086 void tst_QWebFrame::enumerate()
2088 QFETCH(QStringList, expectedNames);
2090 MyEnumTestQObject enumQObject;
2091 // give it some dynamic properties
2092 enumQObject.setProperty("dp1", "dp1");
2093 enumQObject.setProperty("dp2", "dp2");
2094 enumQObject.setProperty("dp3", "dp3");
2095 m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
2097 // enumerate in script
2099 evalJS("var enumeratedProperties = []");
2100 evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
2101 QStringList result = evalJSV("enumeratedProperties").toStringList();
2102 QCOMPARE(result.size(), expectedNames.size());
2103 for (int i = 0; i < expectedNames.size(); ++i)
2104 QCOMPARE(result.at(i), expectedNames.at(i));
2108 void tst_QWebFrame::objectDeleted()
2110 MyQObject* qobj = new MyQObject();
2111 m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
2112 evalJS("bar.objectName = 'foo';");
2113 QCOMPARE(qobj->objectName(), QLatin1String("foo"));
2114 evalJS("bar.intProperty = 123;");
2115 QCOMPARE(qobj->intProperty(), 123);
2116 qobj->resetQtFunctionInvoked();
2117 evalJS("bar.myInvokable.call(bar);");
2118 QCOMPARE(qobj->qtFunctionInvoked(), 0);
2120 // do this, to ensure that we cache that it implements call
2123 // now delete the object
2126 QCOMPARE(evalJS("typeof bar"), sObject);
2128 // any attempt to access properties of the object should result in an exception
2131 QString ret = evalJS("bar.objectName", type);
2132 QCOMPARE(type, sError);
2133 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
2137 QString ret = evalJS("bar.objectName = 'foo'", type);
2138 QCOMPARE(type, sError);
2139 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
2142 // myInvokable is stored in member table (since we've accessed it before deletion)
2145 evalJS("bar.myInvokable", type);
2146 QCOMPARE(type, sFunction);
2151 QString ret = evalJS("bar.myInvokable.call(bar);", type);
2152 ret = evalJS("bar.myInvokable(bar)", type);
2153 QCOMPARE(type, sError);
2154 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
2156 // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
2159 QString ret = evalJS("bar.myInvokableWithIntArg", type);
2160 QCOMPARE(type, sError);
2161 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
2164 // access from script
2165 evalJS("window.o = bar;");
2168 QString ret = evalJS("o.objectName", type);
2169 QCOMPARE(type, sError);
2170 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
2174 QString ret = evalJS("o.myInvokable()", type);
2175 QCOMPARE(type, sError);
2176 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
2180 QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
2181 QCOMPARE(type, sError);
2182 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
2186 void tst_QWebFrame::typeConversion()
2188 m_myObject->resetQtFunctionInvoked();
2190 QDateTime localdt(QDate(2008,1,18), QTime(12,31,0));
2191 QDateTime utclocaldt = localdt.toUTC();
2192 QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC);
2194 // Dates in JS (default to local)
2195 evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
2196 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2197 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2198 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
2200 m_myObject->resetQtFunctionInvoked();
2201 evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
2202 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2203 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2204 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
2206 // Pushing QDateTimes into JS
2208 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
2209 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
2210 m_myObject->emitMySignalWithDateTimeArg(localdt);
2211 QCOMPARE(evalJS("window.__date_equals"), sTrue);
2212 evalJS("delete window.__date_equals");
2213 m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
2214 QCOMPARE(evalJS("window.__date_equals"), sTrue);
2215 evalJS("delete window.__date_equals");
2216 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
2219 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
2220 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
2221 m_myObject->emitMySignalWithDateTimeArg(utcdt);
2222 QCOMPARE(evalJS("window.__date_equals"), sTrue);
2223 evalJS("delete window.__date_equals");
2224 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
2229 class StringListTestObject : public QObject {
2232 QVariant stringList()
2234 return QStringList() << "Q" << "t";
2238 void tst_QWebFrame::arrayObjectEnumerable()
2241 QWebFrame* frame = page.mainFrame();
2242 QObject* qobject = new StringListTestObject();
2243 frame->addToJavaScriptWindowObject("test", qobject, QScriptEngine::ScriptOwnership);
2245 const QString script("var stringArray = test.stringList();"
2247 "for (var i in stringArray) {"
2248 " result += stringArray[i];"
2251 QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt"));
2254 void tst_QWebFrame::symmetricUrl()
2256 QVERIFY(m_view->url().isEmpty());
2258 QCOMPARE(m_view->history()->count(), 0);
2260 QUrl dataUrl("data:text/html,<h1>Test");
2262 m_view->setUrl(dataUrl);
2263 QCOMPARE(m_view->url(), dataUrl);
2264 QCOMPARE(m_view->history()->count(), 0);
2266 // loading is _not_ immediate, so the text isn't set just yet.
2267 QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty());
2269 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2271 QCOMPARE(m_view->history()->count(), 1);
2272 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test"));
2274 QUrl dataUrl2("data:text/html,<h1>Test2");
2275 QUrl dataUrl3("data:text/html,<h1>Test3");
2277 m_view->setUrl(dataUrl2);
2278 m_view->setUrl(dataUrl3);
2280 QCOMPARE(m_view->url(), dataUrl3);
2282 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2284 QCOMPARE(m_view->history()->count(), 2);
2286 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3"));
2289 void tst_QWebFrame::progressSignal()
2291 QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int)));
2293 QUrl dataUrl("data:text/html,<h1>Test");
2294 m_view->setUrl(dataUrl);
2296 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2298 QVERIFY(progressSpy.size() >= 2);
2300 // WebKit defines initialProgressValue as 10%, not 0%
2301 QCOMPARE(progressSpy.first().first().toInt(), 10);
2303 // But we always end at 100%
2304 QCOMPARE(progressSpy.last().first().toInt(), 100);
2307 void tst_QWebFrame::urlChange()
2309 QSignalSpy urlSpy(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
2311 QUrl dataUrl("data:text/html,<h1>Test");
2312 m_view->setUrl(dataUrl);
2314 ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
2316 QCOMPARE(urlSpy.size(), 1);
2318 QUrl dataUrl2("data:text/html,<html><head><title>title</title></head><body><h1>Test</body></html>");
2319 m_view->setUrl(dataUrl2);
2321 ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
2323 QCOMPARE(urlSpy.size(), 2);
2327 void tst_QWebFrame::domCycles()
2329 m_view->setHtml("<html><body>");
2330 QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
2331 QVERIFY(v.type() == QVariant::Map);
2334 class FakeReply : public QNetworkReply {
2338 FakeReply(const QNetworkRequest& request, QObject* parent = 0)
2339 : QNetworkReply(parent)
2341 setOperation(QNetworkAccessManager::GetOperation);
2342 setRequest(request);
2343 if (request.url() == QUrl("qrc:/test1.html")) {
2344 setHeader(QNetworkRequest::LocationHeader, QString("qrc:/test2.html"));
2345 setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html"));
2347 #ifndef QT_NO_OPENSSL
2348 else if (request.url() == QUrl("qrc:/fake-ssl-error.html"))
2349 setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error !")); // force a ssl error
2351 else if (request.url() == QUrl("http://abcdef.abcdef/"))
2352 setError(QNetworkReply::HostNotFoundError, tr("Invalid URL"));
2354 open(QIODevice::ReadOnly);
2355 QTimer::singleShot(0, this, SLOT(timeout()));
2361 virtual void abort() {}
2362 virtual void close() {}
2365 qint64 readData(char*, qint64)
2373 if (request().url() == QUrl("qrc://test1.html"))
2374 emit error(this->error());
2375 else if (request().url() == QUrl("http://abcdef.abcdef/"))
2376 emit metaDataChanged();
2377 #ifndef QT_NO_OPENSSL
2378 else if (request().url() == QUrl("qrc:/fake-ssl-error.html"))
2387 class FakeNetworkManager : public QNetworkAccessManager {
2391 FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { }
2394 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
2396 QString url = request.url().toString();
2397 if (op == QNetworkAccessManager::GetOperation) {
2398 if (url == "qrc:/test1.html" || url == "http://abcdef.abcdef/")
2399 return new FakeReply(request, this);
2400 #ifndef QT_NO_OPENSSL
2401 else if (url == "qrc:/fake-ssl-error.html") {
2402 FakeReply* reply = new FakeReply(request, this);
2403 QList<QSslError> errors;
2404 emit sslErrors(reply, errors << QSslError(QSslError::UnspecifiedError));
2410 return QNetworkAccessManager::createRequest(op, request, outgoingData);
2414 void tst_QWebFrame::requestedUrl()
2417 QWebFrame* frame = page.mainFrame();
2419 // in few seconds, the image should be completely loaded
2420 QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
2421 FakeNetworkManager* networkManager = new FakeNetworkManager(&page);
2422 page.setNetworkAccessManager(networkManager);
2424 frame->setUrl(QUrl("qrc:/test1.html"));
2425 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2426 QCOMPARE(spy.count(), 1);
2427 QCOMPARE(frame->requestedUrl(), QUrl("qrc:/test1.html"));
2428 QCOMPARE(frame->url(), QUrl("qrc:/test2.html"));
2430 frame->setUrl(QUrl("qrc:/non-existent.html"));
2431 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2432 QCOMPARE(spy.count(), 2);
2433 QCOMPARE(frame->requestedUrl(), QUrl("qrc:/non-existent.html"));
2434 QCOMPARE(frame->url(), QUrl("qrc:/non-existent.html"));
2436 frame->setUrl(QUrl("http://abcdef.abcdef"));
2437 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2438 QCOMPARE(spy.count(), 3);
2439 QCOMPARE(frame->requestedUrl(), QUrl("http://abcdef.abcdef/"));
2440 QCOMPARE(frame->url(), QUrl("http://abcdef.abcdef/"));
2442 #ifndef QT_NO_OPENSSL
2443 qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
2444 qRegisterMetaType<QNetworkReply* >("QNetworkReply*");
2446 QSignalSpy spy2(page.networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
2447 frame->setUrl(QUrl("qrc:/fake-ssl-error.html"));
2448 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2449 QCOMPARE(spy2.count(), 1);
2450 QCOMPARE(frame->requestedUrl(), QUrl("qrc:/fake-ssl-error.html"));
2451 QCOMPARE(frame->url(), QUrl("qrc:/fake-ssl-error.html"));
2455 void tst_QWebFrame::javaScriptWindowObjectCleared_data()
2457 QTest::addColumn<QString>("html");
2458 QTest::addColumn<int>("signalCount");
2459 QTest::newRow("with <script>") << "<html><body><script></script><p>hello world</p></body></html>" << 1;
2460 QTest::newRow("without <script>") << "<html><body><p>hello world</p></body></html>" << 0;
2463 void tst_QWebFrame::javaScriptWindowObjectCleared()
2466 QWebFrame* frame = page.mainFrame();
2467 QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
2468 QFETCH(QString, html);
2469 frame->setHtml(html);
2471 QFETCH(int, signalCount);
2472 QCOMPARE(spy.count(), signalCount);
2475 void tst_QWebFrame::javaScriptWindowObjectClearedOnEvaluate()
2478 QWebFrame* frame = page.mainFrame();
2479 QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
2480 frame->setHtml("<html></html>");
2481 QCOMPARE(spy.count(), 0);
2482 frame->evaluateJavaScript("var a = 'a';");
2483 QCOMPARE(spy.count(), 1);
2484 // no new clear for a new script:
2485 frame->evaluateJavaScript("var a = 1;");
2486 QCOMPARE(spy.count(), 1);
2489 void tst_QWebFrame::setHtml()
2491 QString html("<html><head></head><body><p>hello world</p></body></html>");
2492 m_view->page()->mainFrame()->setHtml(html);
2493 QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
2496 void tst_QWebFrame::setHtmlWithResource()
2498 QString html("<html><body><p>hello world</p><img src='qrc:/image.png'/></body></html>");
2501 QWebFrame* frame = page.mainFrame();
2503 // in few seconds, the image should be completey loaded
2504 QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
2505 frame->setHtml(html);
2506 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2507 QCOMPARE(spy.count(), 1);
2509 QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
2510 QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
2511 QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
2516 "<link rel='stylesheet' href='qrc:/style.css' type='text/css' />"
2519 "<p id='idP'>some text</p>"
2523 // in few seconds, the CSS should be completey loaded
2524 frame->setHtml(html2);
2525 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2526 QCOMPARE(spy.size(), 2);
2528 QWebElement p = frame->documentElement().findAll("p").at(0);
2529 QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("red"));
2532 void tst_QWebFrame::setHtmlWithBaseURL()
2534 if (!QDir(TESTS_SOURCE_DIR).exists())
2535 QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
2537 QDir::setCurrent(TESTS_SOURCE_DIR);
2539 QString html("<html><body><p>hello world</p><img src='resources/image2.png'/></body></html>");
2542 QWebFrame* frame = page.mainFrame();
2544 // in few seconds, the image should be completey loaded
2545 QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
2547 frame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
2548 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2549 QCOMPARE(spy.count(), 1);
2551 QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
2552 QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
2553 QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
2555 // no history item has to be added.
2556 QCOMPARE(m_view->page()->history()->count(), 0);
2559 class MyPage : public QWebPage
2562 MyPage() : QWebPage(), alerts(0) {}
2566 virtual void javaScriptAlert(QWebFrame*, const QString& msg)
2569 QCOMPARE(msg, QString("foo"));
2570 // Should not be enough to trigger deferred loading, since we've upped the HTML
2571 // tokenizer delay in the Qt frameloader. See HTMLTokenizer::continueProcessing()
2576 void tst_QWebFrame::setHtmlWithJSAlert()
2578 QString html("<html><head></head><body><script>alert('foo');</script><p>hello world</p></body></html>");
2580 m_view->setPage(&page);
2581 page.mainFrame()->setHtml(html);
2582 QCOMPARE(page.alerts, 1);
2583 QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
2586 class TestNetworkManager : public QNetworkAccessManager
2589 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
2591 QList<QUrl> requestedUrls;
2594 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
2595 requestedUrls.append(request.url());
2596 QNetworkRequest redirectedRequest = request;
2597 redirectedRequest.setUrl(QUrl("data:text/html,<p>hello"));
2598 return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData);
2602 void tst_QWebFrame::ipv6HostEncoding()
2604 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
2605 m_page->setNetworkAccessManager(networkManager);
2606 networkManager->requestedUrls.clear();
2608 QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html");
2609 m_view->setHtml("<p>Hi", baseUrl);
2610 m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();"
2611 "r.open('GET', 'http://[::1]/test.xml', false);"
2614 QCOMPARE(networkManager->requestedUrls.count(), 1);
2615 QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml"));
2618 void tst_QWebFrame::metaData()
2620 m_view->setHtml("<html>"
2622 " <meta name=\"description\" content=\"Test description\">"
2623 " <meta name=\"keywords\" content=\"HTML, JavaScript, Css\">"
2627 QMultiMap<QString, QString> metaData = m_view->page()->mainFrame()->metaData();
2629 QCOMPARE(metaData.count(), 2);
2631 QCOMPARE(metaData.value("description"), QString("Test description"));
2632 QCOMPARE(metaData.value("keywords"), QString("HTML, JavaScript, Css"));
2633 QCOMPARE(metaData.value("nonexistant"), QString());
2635 m_view->setHtml("<html>"
2637 " <meta name=\"samekey\" content=\"FirstValue\">"
2638 " <meta name=\"samekey\" content=\"SecondValue\">"
2642 metaData = m_view->page()->mainFrame()->metaData();
2644 QCOMPARE(metaData.count(), 2);
2646 QStringList values = metaData.values("samekey");
2647 QCOMPARE(values.count(), 2);
2649 QVERIFY(values.contains("FirstValue"));
2650 QVERIFY(values.contains("SecondValue"));
2652 QCOMPARE(metaData.value("nonexistant"), QString());
2655 #if !defined(Q_WS_MAEMO_5)
2656 void tst_QWebFrame::popupFocus()
2659 view.setHtml("<html>"
2661 " <select name=\"select\">"
2662 " <option>1</option>"
2663 " <option>2</option>"
2665 " <input type=\"text\"> </input>"
2666 " <textarea name=\"text_area\" rows=\"3\" cols=\"40\">"
2667 "This test checks whether showing and hiding a popup"
2668 "takes the focus away from the webpage."
2672 view.resize(400, 100);
2675 QTRY_VERIFY(view.hasFocus());
2677 // open the popup by clicking. check if focus is on the popup
2678 QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(25, 25));
2679 QObject* webpopup = firstChildByClassName(&view, "QComboBox");
2680 QComboBox* combo = qobject_cast<QComboBox*>(webpopup);
2681 QVERIFY(combo != 0);
2682 QTRY_VERIFY(!view.hasFocus() && combo->view()->hasFocus()); // Focus should be on the popup
2684 // hide the popup and check if focus is on the page
2686 QTRY_VERIFY(view.hasFocus() && !combo->view()->hasFocus()); // Focus should be back on the WebView
2690 void tst_QWebFrame::inputFieldFocus()
2693 view.setHtml("<html><body><input type=\"text\"></input></body></html>");
2694 view.resize(400, 100);
2697 QTRY_VERIFY(view.hasFocus());
2699 // double the flashing time, should at least blink once already
2700 int delay = qApp->cursorFlashTime() * 2;
2702 // focus the lineedit and check if it blinks
2703 QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(25, 25));
2704 m_inputFieldsTestView = &view;
2705 view.installEventFilter( this );
2706 QTest::qWait(delay);
2707 QVERIFY2(m_inputFieldTestPaintCount >= 3,
2708 "The input field should have a blinking caret");
2711 void tst_QWebFrame::hitTestContent()
2713 QString html("<html><body><p>A paragraph</p><br/><br/><br/><a href=\"about:blank\" target=\"_foo\">link text</a></body></html>");
2716 QWebFrame* frame = page.mainFrame();
2717 frame->setHtml(html);
2718 page.setViewportSize(QSize(200, 0)); //no height so link is not visible
2719 QWebHitTestResult result = frame->hitTestContent(QPoint(10, 100));
2720 QCOMPARE(result.linkText(), QString("link text"));
2721 QWebElement link = result.linkElement();
2722 QCOMPARE(link.attribute("target"), QString("_foo"));
2725 void tst_QWebFrame::jsByteArray()
2727 QByteArray ba("hello world");
2728 m_myObject->setByteArrayProperty(ba);
2730 // read-only property
2731 QCOMPARE(m_myObject->byteArrayProperty(), ba);
2733 QVariant v = evalJSV("myObject.byteArrayProperty");
2734 QCOMPARE(int(v.type()), int(QVariant::ByteArray));
2736 QCOMPARE(v.toByteArray(), ba);
2739 void tst_QWebFrame::ownership()
2743 QPointer<QObject> ptr = new QObject();
2747 QWebFrame* frame = page.mainFrame();
2748 frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::ScriptOwnership);
2753 QPointer<QObject> ptr = new QObject();
2755 QObject* before = ptr;
2758 QWebFrame* frame = page.mainFrame();
2759 frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::QtOwnership);
2761 QVERIFY(ptr == before);
2765 QObject* parent = new QObject();
2766 QObject* child = new QObject(parent);
2768 QWebFrame* frame = page.mainFrame();
2769 frame->addToJavaScriptWindowObject("test", child, QScriptEngine::QtOwnership);
2770 QVariant v = frame->evaluateJavaScript("test");
2771 QCOMPARE(qvariant_cast<QObject*>(v), child);
2773 v = frame->evaluateJavaScript("test");
2774 QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0);
2777 QPointer<QObject> ptr = new QObject();
2781 QWebFrame* frame = page.mainFrame();
2782 frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::AutoOwnership);
2784 // no parent, so it should be like ScriptOwnership
2788 QObject* parent = new QObject();
2789 QPointer<QObject> child = new QObject(parent);
2790 QVERIFY(child != 0);
2793 QWebFrame* frame = page.mainFrame();
2794 frame->addToJavaScriptWindowObject("test", child, QScriptEngine::AutoOwnership);
2796 // has parent, so it should be like QtOwnership
2797 QVERIFY(child != 0);
2802 void tst_QWebFrame::nullValue()
2804 QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null");
2805 QVERIFY(v.isNull());
2808 void tst_QWebFrame::baseUrl_data()
2810 QTest::addColumn<QString>("html");
2811 QTest::addColumn<QUrl>("loadUrl");
2812 QTest::addColumn<QUrl>("url");
2813 QTest::addColumn<QUrl>("baseUrl");
2815 QTest::newRow("null") << QString() << QUrl()
2816 << QUrl("about:blank") << QUrl("about:blank");
2818 QTest::newRow("foo") << QString() << QUrl("http://foobar.baz/")
2819 << QUrl("http://foobar.baz/") << QUrl("http://foobar.baz/");
2821 QString html = "<html>"
2823 "<base href=\"http://foobaz.bar/\" />"
2826 QTest::newRow("customBaseUrl") << html << QUrl("http://foobar.baz/")
2827 << QUrl("http://foobar.baz/") << QUrl("http://foobaz.bar/");
2830 void tst_QWebFrame::baseUrl()
2832 QFETCH(QString, html);
2833 QFETCH(QUrl, loadUrl);
2835 QFETCH(QUrl, baseUrl);
2837 m_page->mainFrame()->setHtml(html, loadUrl);
2838 QCOMPARE(m_page->mainFrame()->url(), url);
2839 QCOMPARE(m_page->mainFrame()->baseUrl(), baseUrl);
2842 void tst_QWebFrame::hasSetFocus()
2844 QString html("<html><body><p>top</p>" \
2845 "<iframe width='80%' height='30%'/>" \
2848 QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
2849 m_page->mainFrame()->setHtml(html);
2851 waitForSignal(m_page->mainFrame(), SIGNAL(loadFinished(bool)), 200);
2852 QCOMPARE(loadSpy.size(), 1);
2854 QList<QWebFrame*> children = m_page->mainFrame()->childFrames();
2855 QWebFrame* frame = children.at(0);
2856 QString innerHtml("<html><body><p>another iframe</p>" \
2857 "<iframe width='80%' height='30%'/>" \
2859 frame->setHtml(innerHtml);
2861 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2862 QCOMPARE(loadSpy.size(), 2);
2864 m_page->mainFrame()->setFocus();
2865 QTRY_VERIFY(m_page->mainFrame()->hasFocus());
2867 for (int i = 0; i < children.size(); ++i) {
2868 children.at(i)->setFocus();
2869 QTRY_VERIFY(children.at(i)->hasFocus());
2870 QVERIFY(!m_page->mainFrame()->hasFocus());
2873 m_page->mainFrame()->setFocus();
2874 QTRY_VERIFY(m_page->mainFrame()->hasFocus());
2877 void tst_QWebFrame::render()
2879 QString html("<html>" \
2881 "body, iframe { margin: 0px; border: none; }" \
2883 "<body><iframe width='100px' height='100px'/></body>" \
2887 page.mainFrame()->setHtml(html);
2889 QList<QWebFrame*> frames = page.mainFrame()->childFrames();
2890 QWebFrame *frame = frames.at(0);
2891 QString innerHtml("<body style='margin: 0px;'><img src='qrc:/image.png'/></body>");
2892 frame->setHtml(innerHtml);
2896 QSize size = page.mainFrame()->contentsSize();
2897 page.setViewportSize(size);
2899 // render contents layer only (the iframe is smaller than the image, so it will have scrollbars)
2900 QPainter painter1(&picture);
2901 frame->render(&painter1, QWebFrame::ContentsLayer);
2904 QCOMPARE(size.width(), picture.boundingRect().width() + frame->scrollBarGeometry(Qt::Vertical).width());
2905 QCOMPARE(size.height(), picture.boundingRect().height() + frame->scrollBarGeometry(Qt::Horizontal).height());
2907 // render everything, should be the size of the iframe
2908 QPainter painter2(&picture);
2909 frame->render(&painter2, QWebFrame::AllLayers);
2912 QCOMPARE(size.width(), picture.boundingRect().width()); // width: 100px
2913 QCOMPARE(size.height(), picture.boundingRect().height()); // height: 100px
2916 void tst_QWebFrame::scrollPosition()
2918 // enlarged image in a small viewport, to provoke the scrollbars to appear
2919 QString html("<html><body><img src='qrc:/image.png' height=500 width=500/></body></html>");
2922 page.setViewportSize(QSize(200, 200));
2924 QWebFrame* frame = page.mainFrame();
2925 frame->setHtml(html);
2926 frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
2927 frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
2929 // try to set the scroll offset programmatically
2930 frame->setScrollPosition(QPoint(23, 29));
2931 QCOMPARE(frame->scrollPosition().x(), 23);
2932 QCOMPARE(frame->scrollPosition().y(), 29);
2934 int x = frame->evaluateJavaScript("window.scrollX").toInt();
2935 int y = frame->evaluateJavaScript("window.scrollY").toInt();
2940 void tst_QWebFrame::scrollToAnchor()
2943 page.setViewportSize(QSize(480, 800));
2944 QWebFrame* frame = page.mainFrame();
2946 QString html("<html><body><p style=\"margin-bottom: 1500px;\">Hello.</p>"
2947 "<p><a id=\"foo\">This</a> is an anchor</p>"
2948 "<p style=\"margin-bottom: 1500px;\"><a id=\"bar\">This</a> is another anchor</p>"
2950 frame->setHtml(html);
2951 frame->setScrollPosition(QPoint(0, 0));
2952 QCOMPARE(frame->scrollPosition().x(), 0);
2953 QCOMPARE(frame->scrollPosition().y(), 0);
2955 QWebElement fooAnchor = frame->findFirstElement("a[id=foo]");
2957 frame->scrollToAnchor("foo");
2958 QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
2960 frame->scrollToAnchor("bar");
2961 frame->scrollToAnchor("foo");
2962 QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
2964 frame->scrollToAnchor("top");
2965 QCOMPARE(frame->scrollPosition().y(), 0);
2967 frame->scrollToAnchor("bar");
2968 frame->scrollToAnchor("notexist");
2969 QVERIFY(frame->scrollPosition().y() != 0);
2973 void tst_QWebFrame::scrollbarsOff()
2976 QWebFrame* mainFrame = view.page()->mainFrame();
2978 mainFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
2979 mainFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
2981 QString html("<script>" \
2982 " function checkScrollbar() {" \
2983 " if (innerWidth === document.documentElement.offsetWidth)" \
2984 " document.getElementById('span1').innerText = 'SUCCESS';" \
2986 " document.getElementById('span1').innerText = 'FAIL';" \
2990 " <div style='margin-top:1000px ; margin-left:1000px'>" \
2991 " <a id='offscreen' href='a'>End</a>" \
2993 "<span id='span1'></span>" \
2998 ::waitForSignal(&view, SIGNAL(loadFinished(bool)));
3000 mainFrame->evaluateJavaScript("checkScrollbar();");
3001 QCOMPARE(mainFrame->documentElement().findAll("span").at(0).toPlainText(), QString("SUCCESS"));
3004 void tst_QWebFrame::evaluateWillCauseRepaint()
3007 QString html("<html><body>top<div id=\"junk\" style=\"display: block;\">"
3008 "junk</div>bottom</body></html>");
3012 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
3013 QTest::qWaitForWindowShown(&view);
3018 view.page()->mainFrame()->evaluateJavaScript(
3019 "document.getElementById('junk').style.display = 'none';");
3021 ::waitForSignal(view.page(), SIGNAL(repaintRequested(QRect)));
3024 class TestFactory : public QObject
3029 : obj(0), counter(0)
3032 Q_INVOKABLE QObject* getNewObject()
3035 obj = new QObject(this);
3036 obj->setObjectName(QLatin1String("test") + QString::number(++counter));
3045 void tst_QWebFrame::qObjectWrapperWithSameIdentity()
3047 m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>"
3048 "<body><span id='span1'>test</span></body>");
3050 QWebFrame* mainFrame = m_view->page()->mainFrame();
3051 QCOMPARE(mainFrame->toPlainText(), QString("test"));
3053 mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QScriptEngine::ScriptOwnership);
3055 mainFrame->evaluateJavaScript("triggerBug();");
3056 QCOMPARE(mainFrame->toPlainText(), QString("test1"));
3058 mainFrame->evaluateJavaScript("triggerBug();");
3059 QCOMPARE(mainFrame->toPlainText(), QString("test2"));
3062 void tst_QWebFrame::introspectQtMethods_data()
3064 QTest::addColumn<QString>("objectExpression");
3065 QTest::addColumn<QString>("methodName");
3066 QTest::addColumn<QStringList>("expectedPropertyNames");
3068 QTest::newRow("myObject.mySignal")
3069 << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name");
3070 QTest::newRow("myObject.mySlot")
3071 << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name");
3072 QTest::newRow("myObject.myInvokable")
3073 << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name");
3074 QTest::newRow("myObject.mySignal.connect")
3075 << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name");
3076 QTest::newRow("myObject.mySignal.disconnect")
3077 << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name");
3080 void tst_QWebFrame::introspectQtMethods()
3082 QFETCH(QString, objectExpression);
3083 QFETCH(QString, methodName);
3084 QFETCH(QStringList, expectedPropertyNames);
3086 QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName);
3087 QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames);
3089 for (int i = 0; i < expectedPropertyNames.size(); ++i) {
3090 QString name = expectedPropertyNames.at(i);
3091 QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue);
3092 evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name));
3093 QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object"));
3094 QCOMPARE(evalJS("descriptor.get"), sUndefined);
3095 QCOMPARE(evalJS("descriptor.set"), sUndefined);
3096 QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue);
3097 QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse);
3098 QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse);
3101 QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty());
3104 QTEST_MAIN(tst_QWebFrame)
3105 #include "tst_qwebframe.moc"