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>
38 #include <qsslerror.h>
41 #include "../WebCoreSupport/DumpRenderTreeSupportQt.h"
46 Q_DECLARE_METATYPE(CustomType)
48 Q_DECLARE_METATYPE(QBrush*)
49 Q_DECLARE_METATYPE(QObjectList)
50 Q_DECLARE_METATYPE(QList<int>)
51 Q_DECLARE_METATYPE(Qt::BrushStyle)
52 Q_DECLARE_METATYPE(QVariantList)
53 Q_DECLARE_METATYPE(QVariantMap)
55 class MyQObject : public QObject
59 Q_PROPERTY(int intProperty READ intProperty WRITE setIntProperty)
60 Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty)
61 Q_PROPERTY(QVariantList variantListProperty READ variantListProperty WRITE setVariantListProperty)
62 Q_PROPERTY(QVariantMap variantMapProperty READ variantMapProperty WRITE setVariantMapProperty)
63 Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty)
64 Q_PROPERTY(QStringList stringListProperty READ stringListProperty WRITE setStringListProperty)
65 Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty)
66 Q_PROPERTY(QBrush brushProperty READ brushProperty WRITE setBrushProperty)
67 Q_PROPERTY(double hiddenProperty READ hiddenProperty WRITE setHiddenProperty SCRIPTABLE false)
68 Q_PROPERTY(int writeOnlyProperty WRITE setWriteOnlyProperty)
69 Q_PROPERTY(int readOnlyProperty READ readOnlyProperty)
70 Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
71 Q_PROPERTY(CustomType propWithCustomType READ propWithCustomType WRITE setPropWithCustomType)
72 Q_PROPERTY(QWebElement webElementProperty READ webElementProperty WRITE setWebElementProperty)
73 Q_PROPERTY(QObject* objectStarProperty READ objectStarProperty WRITE setObjectStarProperty)
74 Q_ENUMS(Policy Strategy)
95 AllAbility = FooAbility | BarAbility | BazAbility
98 Q_DECLARE_FLAGS(Ability, AbilityFlag)
100 MyQObject(QObject* parent = 0)
103 m_variantValue(QLatin1String("foo")),
104 m_variantListValue(QVariantList() << QVariant(123) << QVariant(QLatin1String("foo"))),
105 m_stringValue(QLatin1String("bar")),
106 m_stringListValue(QStringList() << QLatin1String("zig") << QLatin1String("zag")),
107 m_brushValue(QColor(10, 20, 30, 40)),
108 m_hiddenValue(456.0),
109 m_writeOnlyValue(789),
110 m_readOnlyValue(987),
112 m_qtFunctionInvoked(-1)
114 m_variantMapValue.insert("a", QVariant(123));
115 m_variantMapValue.insert("b", QVariant(QLatin1String("foo")));
116 m_variantMapValue.insert("c", QVariant::fromValue<QObject*>(this));
121 int intProperty() const {
124 void setIntProperty(int value) {
128 QVariant variantProperty() const {
129 return m_variantValue;
131 void setVariantProperty(const QVariant &value) {
132 m_variantValue = value;
135 QVariantList variantListProperty() const {
136 return m_variantListValue;
138 void setVariantListProperty(const QVariantList &value) {
139 m_variantListValue = value;
142 QVariantMap variantMapProperty() const {
143 return m_variantMapValue;
145 void setVariantMapProperty(const QVariantMap &value) {
146 m_variantMapValue = value;
149 QString stringProperty() const {
150 return m_stringValue;
152 void setStringProperty(const QString &value) {
153 m_stringValue = value;
156 QStringList stringListProperty() const {
157 return m_stringListValue;
159 void setStringListProperty(const QStringList &value) {
160 m_stringListValue = value;
163 QByteArray byteArrayProperty() const {
164 return m_byteArrayValue;
166 void setByteArrayProperty(const QByteArray &value) {
167 m_byteArrayValue = value;
170 QBrush brushProperty() const {
173 Q_INVOKABLE void setBrushProperty(const QBrush &value) {
174 m_brushValue = value;
177 double hiddenProperty() const {
178 return m_hiddenValue;
180 void setHiddenProperty(double value) {
181 m_hiddenValue = value;
184 int writeOnlyProperty() const {
185 return m_writeOnlyValue;
187 void setWriteOnlyProperty(int value) {
188 m_writeOnlyValue = value;
191 int readOnlyProperty() const {
192 return m_readOnlyValue;
195 QKeySequence shortcut() const {
198 void setShortcut(const QKeySequence &seq) {
202 QWebElement webElementProperty() const {
206 void setWebElementProperty(const QWebElement& element) {
207 m_webElement = element;
210 CustomType propWithCustomType() const {
213 void setPropWithCustomType(const CustomType &c) {
217 QObject* objectStarProperty() const {
221 void setObjectStarProperty(QObject* object) {
222 m_objectStar = object;
226 int qtFunctionInvoked() const {
227 return m_qtFunctionInvoked;
230 QVariantList qtFunctionActuals() const {
234 void resetQtFunctionInvoked() {
235 m_qtFunctionInvoked = -1;
239 Q_INVOKABLE void myInvokable() {
240 m_qtFunctionInvoked = 0;
242 Q_INVOKABLE void myInvokableWithIntArg(int arg) {
243 m_qtFunctionInvoked = 1;
246 Q_INVOKABLE void myInvokableWithLonglongArg(qlonglong arg) {
247 m_qtFunctionInvoked = 2;
250 Q_INVOKABLE void myInvokableWithFloatArg(float arg) {
251 m_qtFunctionInvoked = 3;
254 Q_INVOKABLE void myInvokableWithDoubleArg(double arg) {
255 m_qtFunctionInvoked = 4;
258 Q_INVOKABLE void myInvokableWithStringArg(const QString &arg) {
259 m_qtFunctionInvoked = 5;
262 Q_INVOKABLE void myInvokableWithIntArgs(int arg1, int arg2) {
263 m_qtFunctionInvoked = 6;
264 m_actuals << arg1 << arg2;
266 Q_INVOKABLE int myInvokableReturningInt() {
267 m_qtFunctionInvoked = 7;
270 Q_INVOKABLE qlonglong myInvokableReturningLongLong() {
271 m_qtFunctionInvoked = 39;
274 Q_INVOKABLE QString myInvokableReturningString() {
275 m_qtFunctionInvoked = 8;
276 return QLatin1String("ciao");
278 Q_INVOKABLE void myInvokableWithIntArg(int arg1, int arg2) { // overload
279 m_qtFunctionInvoked = 9;
280 m_actuals << arg1 << arg2;
282 Q_INVOKABLE void myInvokableWithEnumArg(Policy policy) {
283 m_qtFunctionInvoked = 10;
286 Q_INVOKABLE void myInvokableWithQualifiedEnumArg(MyQObject::Policy policy) {
287 m_qtFunctionInvoked = 36;
290 Q_INVOKABLE Policy myInvokableReturningEnum() {
291 m_qtFunctionInvoked = 37;
294 Q_INVOKABLE MyQObject::Policy myInvokableReturningQualifiedEnum() {
295 m_qtFunctionInvoked = 38;
298 Q_INVOKABLE QVector<int> myInvokableReturningVectorOfInt() {
299 m_qtFunctionInvoked = 11;
300 return QVector<int>();
302 Q_INVOKABLE void myInvokableWithVectorOfIntArg(const QVector<int> &) {
303 m_qtFunctionInvoked = 12;
305 Q_INVOKABLE QObject* myInvokableReturningQObjectStar() {
306 m_qtFunctionInvoked = 13;
309 Q_INVOKABLE QObjectList myInvokableWithQObjectListArg(const QObjectList &lst) {
310 m_qtFunctionInvoked = 14;
311 m_actuals << qVariantFromValue(lst);
314 Q_INVOKABLE QVariant myInvokableWithVariantArg(const QVariant &v) {
315 m_qtFunctionInvoked = 15;
319 Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) {
320 m_qtFunctionInvoked = 16;
324 Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) {
325 m_qtFunctionInvoked = 17;
326 m_actuals << qVariantFromValue(lst);
329 Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject* obj) {
330 m_qtFunctionInvoked = 18;
331 m_actuals << qVariantFromValue(obj);
334 Q_INVOKABLE QBrush myInvokableWithQBrushArg(const QBrush &brush) {
335 m_qtFunctionInvoked = 19;
336 m_actuals << qVariantFromValue(brush);
339 Q_INVOKABLE void myInvokableWithBrushStyleArg(Qt::BrushStyle style) {
340 m_qtFunctionInvoked = 43;
341 m_actuals << qVariantFromValue(style);
343 Q_INVOKABLE void myInvokableWithVoidStarArg(void* arg) {
344 m_qtFunctionInvoked = 44;
345 m_actuals << qVariantFromValue(arg);
347 Q_INVOKABLE void myInvokableWithAmbiguousArg(int arg) {
348 m_qtFunctionInvoked = 45;
349 m_actuals << qVariantFromValue(arg);
351 Q_INVOKABLE void myInvokableWithAmbiguousArg(uint arg) {
352 m_qtFunctionInvoked = 46;
353 m_actuals << qVariantFromValue(arg);
355 Q_INVOKABLE void myInvokableWithDefaultArgs(int arg1, const QString &arg2 = "") {
356 m_qtFunctionInvoked = 47;
357 m_actuals << qVariantFromValue(arg1) << qVariantFromValue(arg2);
359 Q_INVOKABLE QObject& myInvokableReturningRef() {
360 m_qtFunctionInvoked = 48;
363 Q_INVOKABLE const QObject& myInvokableReturningConstRef() const {
364 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 49;
367 Q_INVOKABLE void myInvokableWithPointArg(const QPoint &arg) {
368 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 50;
369 m_actuals << qVariantFromValue(arg);
371 Q_INVOKABLE void myInvokableWithPointArg(const QPointF &arg) {
372 const_cast<MyQObject*>(this)->m_qtFunctionInvoked = 51;
373 m_actuals << qVariantFromValue(arg);
375 Q_INVOKABLE void myInvokableWithBoolArg(bool arg) {
376 m_qtFunctionInvoked = 52;
380 void emitMySignal() {
383 void emitMySignalWithIntArg(int arg) {
384 emit mySignalWithIntArg(arg);
386 void emitMySignal2(bool arg) {
389 void emitMySignal2() {
392 void emitMySignalWithDateTimeArg(QDateTime dt) {
393 emit mySignalWithDateTimeArg(dt);
395 void emitMySignalWithRegexArg(QRegExp r) {
396 emit mySignalWithRegexArg(r);
401 m_qtFunctionInvoked = 20;
403 void mySlotWithIntArg(int arg) {
404 m_qtFunctionInvoked = 21;
407 void mySlotWithDoubleArg(double arg) {
408 m_qtFunctionInvoked = 22;
411 void mySlotWithStringArg(const QString &arg) {
412 m_qtFunctionInvoked = 23;
416 void myOverloadedSlot() {
417 m_qtFunctionInvoked = 24;
419 void myOverloadedSlot(QObject* arg) {
420 m_qtFunctionInvoked = 41;
421 m_actuals << qVariantFromValue(arg);
423 void myOverloadedSlot(bool arg) {
424 m_qtFunctionInvoked = 25;
427 void myOverloadedSlot(const QStringList &arg) {
428 m_qtFunctionInvoked = 42;
431 void myOverloadedSlot(double arg) {
432 m_qtFunctionInvoked = 26;
435 void myOverloadedSlot(float arg) {
436 m_qtFunctionInvoked = 27;
439 void myOverloadedSlot(int arg) {
440 m_qtFunctionInvoked = 28;
443 void myOverloadedSlot(const QString &arg) {
444 m_qtFunctionInvoked = 29;
447 void myOverloadedSlot(const QColor &arg) {
448 m_qtFunctionInvoked = 30;
451 void myOverloadedSlot(const QBrush &arg) {
452 m_qtFunctionInvoked = 31;
455 void myOverloadedSlot(const QDateTime &arg) {
456 m_qtFunctionInvoked = 32;
459 void myOverloadedSlot(const QDate &arg) {
460 m_qtFunctionInvoked = 33;
463 void myOverloadedSlot(const QRegExp &arg) {
464 m_qtFunctionInvoked = 34;
467 void myOverloadedSlot(const QVariant &arg) {
468 m_qtFunctionInvoked = 35;
471 void myOverloadedSlot(const QWebElement &arg) {
472 m_qtFunctionInvoked = 36;
473 m_actuals << QVariant::fromValue<QWebElement>(arg);
476 void qscript_call(int arg) {
477 m_qtFunctionInvoked = 40;
482 void myProtectedSlot() {
483 m_qtFunctionInvoked = 36;
487 void myPrivateSlot() { }
491 void mySignalWithIntArg(int arg);
492 void mySignalWithDoubleArg(double arg);
493 void mySignal2(bool arg = false);
494 void mySignalWithDateTimeArg(QDateTime dt);
495 void mySignalWithRegexArg(QRegExp r);
499 QVariant m_variantValue;
500 QVariantList m_variantListValue;
501 QVariantMap m_variantMapValue;
502 QString m_stringValue;
503 QStringList m_stringListValue;
504 QByteArray m_byteArrayValue;
506 double m_hiddenValue;
507 int m_writeOnlyValue;
509 QKeySequence m_shortcut;
510 QWebElement m_webElement;
511 CustomType m_customType;
512 QObject* m_objectStar;
513 int m_qtFunctionInvoked;
514 QVariantList m_actuals;
517 class MyOtherQObject : public MyQObject
520 MyOtherQObject(QObject* parent = 0)
521 : MyQObject(parent) { }
524 class MyEnumTestQObject : public QObject
527 Q_PROPERTY(QString p1 READ p1)
528 Q_PROPERTY(QString p2 READ p2)
529 Q_PROPERTY(QString p3 READ p3 SCRIPTABLE false)
530 Q_PROPERTY(QString p4 READ p4)
531 Q_PROPERTY(QString p5 READ p5 SCRIPTABLE false)
532 Q_PROPERTY(QString p6 READ p6)
534 MyEnumTestQObject(QObject* parent = 0)
535 : QObject(parent) { }
537 return QLatin1String("p1");
540 return QLatin1String("p2");
543 return QLatin1String("p3");
546 return QLatin1String("p4");
549 return QLatin1String("p5");
552 return QLatin1String("p5");
556 void myOtherSlot() { }
561 class tst_QWebFrame : public QObject
567 virtual ~tst_QWebFrame();
568 bool eventFilter(QObject* watched, QEvent* event);
575 void getSetDynamicProperty();
576 void getSetDynamicProperty_data();
577 void getSetChildren();
578 void getSetChildren_data();
579 void getSetStaticProperty();
580 void callQtInvokable();
581 void connectAndDisconnect();
583 void classConstructor();
584 void overrideInvokable();
585 void transferInvokable();
588 void overloadedSlots();
589 void enumerate_data();
591 void objectDeleted();
592 void typeConversion();
593 void arrayObjectEnumerable();
595 void progressSignal();
599 void javaScriptWindowObjectCleared_data();
600 void javaScriptWindowObjectCleared();
601 void javaScriptWindowObjectClearedOnEvaluate();
603 void setHtmlWithResource();
604 void setHtmlWithBaseURL();
605 void setHtmlWithJSAlert();
606 void ipv6HostEncoding();
608 #if !defined(Q_WS_MAEMO_5)
609 // as maemo 5 does not use QComboBoxes to implement the popups
610 // this test does not make sense for it.
613 void inputFieldFocus();
614 void hitTestContent();
622 void scrollPosition();
623 void scrollToAnchor();
624 void scrollbarsOff();
625 void evaluateWillCauseRepaint();
626 void qObjectWrapperWithSameIdentity();
627 void introspectQtMethods_data();
628 void introspectQtMethods();
629 void setContent_data();
633 QString evalJS(const QString&s) {
634 // Convert an undefined return variant to the string "undefined"
635 QVariant ret = evalJSV(s);
636 if (ret.userType() == QMetaType::Void)
639 return ret.toString();
641 QVariant evalJSV(const QString &s) {
642 return m_page->mainFrame()->evaluateJavaScript(s);
645 QString evalJS(const QString&s, QString& type) {
646 return evalJSV(s, type).toString();
648 QVariant evalJSV(const QString &s, QString& type) {
649 // As a special measure, if we get an exception we set the type to 'error'
650 // (in ecma, an Error object has typeof object, but qtscript has a convenience function)
651 // Similarly, an array is an object, but we'd prefer to have a type of 'array'
652 // Also, consider a QMetaType::Void QVariant to be undefined
654 escaped.replace('\'', "\\'"); // Don't preescape your single quotes!
655 evalJS("var retvalue;\
658 retvalue = eval('" + escaped + "'); \
659 typevalue = typeof retvalue; \
660 if (retvalue instanceof Array) \
661 typevalue = 'array'; \
664 retvalue = e.name + ': ' + e.message;\
665 typevalue = 'error';\
667 QVariant ret = evalJSV("retvalue");
668 if (ret.userType() != QMetaType::Void)
669 type = evalJS("typevalue");
671 ret = QString("undefined");
674 evalJS("delete retvalue; delete typevalue");
677 void garbageCollectJS()
679 DumpRenderTreeSupportQt::garbageCollectorCollect();
681 QObject* firstChildByClassName(QObject* parent, const char* className) {
682 const QObjectList & children = parent->children();
683 foreach (QObject* child, children) {
684 if (!strcmp(child->metaObject()->className(), className)) {
692 const QString sFalse;
693 const QString sUndefined;
694 const QString sArray;
695 const QString sFunction;
696 const QString sError;
697 const QString sString;
698 const QString sObject;
699 const QString sNumber;
704 MyQObject* m_myObject;
705 QWebView* m_inputFieldsTestView;
706 int m_inputFieldTestPaintCount;
709 tst_QWebFrame::tst_QWebFrame()
710 : sTrue("true"), sFalse("false"), sUndefined("undefined"), sArray("array"), sFunction("function"), sError("error"),
711 sString("string"), sObject("object"), sNumber("number"), m_inputFieldsTestView(0), m_inputFieldTestPaintCount(0)
715 tst_QWebFrame::~tst_QWebFrame()
719 bool tst_QWebFrame::eventFilter(QObject* watched, QEvent* event)
721 // used on the inputFieldFocus test
722 if (watched == m_inputFieldsTestView) {
723 if (event->type() == QEvent::Paint)
724 m_inputFieldTestPaintCount++;
726 return QObject::eventFilter(watched, event);
729 void tst_QWebFrame::init()
731 m_view = new QWebView();
732 m_page = m_view->page();
733 m_myObject = new MyQObject();
734 m_page->mainFrame()->addToJavaScriptWindowObject("myObject", m_myObject);
737 void tst_QWebFrame::cleanup()
743 void tst_QWebFrame::getSetStaticProperty()
745 m_page->mainFrame()->setHtml("<html><head><body></body></html>");
746 QCOMPARE(evalJS("typeof myObject.noSuchProperty"), sUndefined);
748 // initial value (set in MyQObject constructor)
751 QVariant ret = evalJSV("myObject.intProperty", type);
752 QCOMPARE(type, sNumber);
753 QCOMPARE(ret.type(), QVariant::Double);
754 QCOMPARE(ret.toInt(), 123);
756 QCOMPARE(evalJS("myObject.intProperty === 123.0"), sTrue);
760 QVariant ret = evalJSV("myObject.variantProperty", type);
761 QCOMPARE(type, sString);
762 QCOMPARE(ret.type(), QVariant::String);
763 QCOMPARE(ret.toString(), QLatin1String("foo"));
765 QCOMPARE(evalJS("myObject.variantProperty == 'foo'"), sTrue);
769 QVariant ret = evalJSV("myObject.stringProperty", type);
770 QCOMPARE(type, sString);
771 QCOMPARE(ret.type(), QVariant::String);
772 QCOMPARE(ret.toString(), QLatin1String("bar"));
774 QCOMPARE(evalJS("myObject.stringProperty === 'bar'"), sTrue);
778 QVariant ret = evalJSV("myObject.variantListProperty", type);
779 QCOMPARE(type, sArray);
780 QCOMPARE(ret.type(), QVariant::List);
781 QVariantList vl = ret.value<QVariantList>();
782 QCOMPARE(vl.size(), 2);
783 QCOMPARE(vl.at(0).toInt(), 123);
784 QCOMPARE(vl.at(1).toString(), QLatin1String("foo"));
786 QCOMPARE(evalJS("myObject.variantListProperty.length === 2"), sTrue);
787 QCOMPARE(evalJS("myObject.variantListProperty[0] === 123"), sTrue);
788 QCOMPARE(evalJS("myObject.variantListProperty[1] === 'foo'"), sTrue);
792 QVariant ret = evalJSV("myObject.variantMapProperty", type);
793 QCOMPARE(type, sObject);
794 QCOMPARE(ret.type(), QVariant::Map);
795 QVariantMap vm = ret.value<QVariantMap>();
796 QCOMPARE(vm.size(), 3);
797 QCOMPARE(vm.value("a").toInt(), 123);
798 QCOMPARE(vm.value("b").toString(), QLatin1String("foo"));
799 QCOMPARE(vm.value("c").value<QObject*>(), static_cast<QObject*>(m_myObject));
801 QCOMPARE(evalJS("myObject.variantMapProperty.a === 123"), sTrue);
802 QCOMPARE(evalJS("myObject.variantMapProperty.b === 'foo'"), sTrue);
803 QCOMPARE(evalJS("myObject.variantMapProperty.c.variantMapProperty.b === 'foo'"), sTrue);
807 QVariant ret = evalJSV("myObject.stringListProperty", type);
808 QCOMPARE(type, sArray);
809 QCOMPARE(ret.type(), QVariant::List);
810 QVariantList vl = ret.value<QVariantList>();
811 QCOMPARE(vl.size(), 2);
812 QCOMPARE(vl.at(0).toString(), QLatin1String("zig"));
813 QCOMPARE(vl.at(1).toString(), QLatin1String("zag"));
815 QCOMPARE(evalJS("myObject.stringListProperty.length === 2"), sTrue);
816 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
817 QCOMPARE(evalJS("myObject.stringListProperty[0]"), QLatin1String("zig"));
818 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
819 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("zag"));
821 // property change in C++ should be reflected in script
822 m_myObject->setIntProperty(456);
823 QCOMPARE(evalJS("myObject.intProperty == 456"), sTrue);
824 m_myObject->setIntProperty(789);
825 QCOMPARE(evalJS("myObject.intProperty == 789"), sTrue);
827 m_myObject->setVariantProperty(QLatin1String("bar"));
828 QCOMPARE(evalJS("myObject.variantProperty === 'bar'"), sTrue);
829 m_myObject->setVariantProperty(42);
830 QCOMPARE(evalJS("myObject.variantProperty === 42"), sTrue);
831 m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
833 // QCOMPARE(evalJS("typeof myObject.variantProperty"), sVariant);
835 m_myObject->setStringProperty(QLatin1String("baz"));
836 QCOMPARE(evalJS("myObject.stringProperty === 'baz'"), sTrue);
837 m_myObject->setStringProperty(QLatin1String("zab"));
838 QCOMPARE(evalJS("myObject.stringProperty === 'zab'"), sTrue);
840 // property change in script should be reflected in C++
841 QCOMPARE(evalJS("myObject.intProperty = 123"), QLatin1String("123"));
842 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
843 QCOMPARE(m_myObject->intProperty(), 123);
844 QCOMPARE(evalJS("myObject.intProperty = 'ciao!';"
845 "myObject.intProperty == 0"), sTrue);
846 QCOMPARE(m_myObject->intProperty(), 0);
847 QCOMPARE(evalJS("myObject.intProperty = '123';"
848 "myObject.intProperty == 123"), sTrue);
849 QCOMPARE(m_myObject->intProperty(), 123);
851 QCOMPARE(evalJS("myObject.stringProperty = 'ciao'"), QLatin1String("ciao"));
852 QCOMPARE(evalJS("myObject.stringProperty"), QLatin1String("ciao"));
853 QCOMPARE(m_myObject->stringProperty(), QLatin1String("ciao"));
854 QCOMPARE(evalJS("myObject.stringProperty = 123;"
855 "myObject.stringProperty"), QLatin1String("123"));
856 QCOMPARE(m_myObject->stringProperty(), QLatin1String("123"));
857 QCOMPARE(evalJS("myObject.stringProperty = null"), QString());
858 QCOMPARE(evalJS("myObject.stringProperty"), QString());
859 QCOMPARE(m_myObject->stringProperty(), QString());
860 QCOMPARE(evalJS("myObject.stringProperty = undefined"), sUndefined);
861 QCOMPARE(evalJS("myObject.stringProperty"), QString());
862 QCOMPARE(m_myObject->stringProperty(), QString());
864 QCOMPARE(evalJS("myObject.variantProperty = new Number(1234);"
865 "myObject.variantProperty").toDouble(), 1234.0);
866 QCOMPARE(m_myObject->variantProperty().toDouble(), 1234.0);
868 QCOMPARE(evalJS("myObject.variantProperty = new Boolean(1234);"
869 "myObject.variantProperty"), sTrue);
870 QCOMPARE(m_myObject->variantProperty().toBool(), true);
872 QCOMPARE(evalJS("myObject.variantProperty = null;"
873 "myObject.variantProperty.valueOf()"), sUndefined);
874 QCOMPARE(m_myObject->variantProperty(), QVariant());
875 QCOMPARE(evalJS("myObject.variantProperty = undefined;"
876 "myObject.variantProperty.valueOf()"), sUndefined);
877 QCOMPARE(m_myObject->variantProperty(), QVariant());
879 QCOMPARE(evalJS("myObject.variantProperty = 'foo';"
880 "myObject.variantProperty.valueOf()"), QLatin1String("foo"));
881 QCOMPARE(m_myObject->variantProperty(), QVariant(QLatin1String("foo")));
882 QCOMPARE(evalJS("myObject.variantProperty = 42;"
883 "myObject.variantProperty").toDouble(), 42.0);
884 QCOMPARE(m_myObject->variantProperty().toDouble(), 42.0);
886 QCOMPARE(evalJS("myObject.variantListProperty = [1, 'two', true];"
887 "myObject.variantListProperty.length == 3"), sTrue);
888 QCOMPARE(evalJS("myObject.variantListProperty[0] === 1"), sTrue);
889 QCOMPARE(evalJS("myObject.variantListProperty[1]"), QLatin1String("two"));
890 QCOMPARE(evalJS("myObject.variantListProperty[2] === true"), sTrue);
892 QCOMPARE(evalJS("myObject.stringListProperty = [1, 'two', true];"
893 "myObject.stringListProperty.length == 3"), sTrue);
894 QCOMPARE(evalJS("typeof myObject.stringListProperty[0]"), sString);
895 QCOMPARE(evalJS("myObject.stringListProperty[0] == '1'"), sTrue);
896 QCOMPARE(evalJS("typeof myObject.stringListProperty[1]"), sString);
897 QCOMPARE(evalJS("myObject.stringListProperty[1]"), QLatin1String("two"));
898 QCOMPARE(evalJS("typeof myObject.stringListProperty[2]"), sString);
899 QCOMPARE(evalJS("myObject.stringListProperty[2]"), QLatin1String("true"));
900 evalJS("myObject.webElementProperty=document.body;");
901 QCOMPARE(evalJS("myObject.webElementProperty.tagName"), QLatin1String("BODY"));
904 QCOMPARE(evalJS("delete myObject.intProperty"), sFalse);
905 QCOMPARE(evalJS("myObject.intProperty == 123"), sTrue);
907 QCOMPARE(evalJS("delete myObject.variantProperty"), sFalse);
908 QCOMPARE(evalJS("myObject.variantProperty").toDouble(), 42.0);
911 QCOMPARE(evalJS("myObject.customProperty"), sUndefined);
912 QCOMPARE(evalJS("myObject.customProperty = 123;"
913 "myObject.customProperty == 123"), sTrue);
914 QVariant v = m_page->mainFrame()->evaluateJavaScript("myObject.customProperty");
915 QCOMPARE(v.type(), QVariant::Double);
916 QCOMPARE(v.toInt(), 123);
918 // non-scriptable property
919 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
920 QCOMPARE(evalJS("myObject.hiddenProperty"), sUndefined);
921 QCOMPARE(evalJS("myObject.hiddenProperty = 123;"
922 "myObject.hiddenProperty == 123"), sTrue);
923 QCOMPARE(m_myObject->hiddenProperty(), 456.0);
925 // write-only property
926 QCOMPARE(m_myObject->writeOnlyProperty(), 789);
927 QCOMPARE(evalJS("typeof myObject.writeOnlyProperty"), sUndefined);
928 QCOMPARE(evalJS("myObject.writeOnlyProperty = 123;"
929 "typeof myObject.writeOnlyProperty"), sUndefined);
930 QCOMPARE(m_myObject->writeOnlyProperty(), 123);
932 // read-only property
933 QCOMPARE(m_myObject->readOnlyProperty(), 987);
934 QCOMPARE(evalJS("myObject.readOnlyProperty == 987"), sTrue);
935 QCOMPARE(evalJS("myObject.readOnlyProperty = 654;"
936 "myObject.readOnlyProperty == 987"), sTrue);
937 QCOMPARE(m_myObject->readOnlyProperty(), 987);
940 m_myObject->setObjectStarProperty(0);
941 QCOMPARE(m_myObject->objectStarProperty(), (QObject*)0);
942 QCOMPARE(evalJS("myObject.objectStarProperty == null"), sTrue);
943 QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
944 QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sFalse);
945 QCOMPARE(evalJS("String(myObject.objectStarProperty) == 'null'"), sTrue);
946 QCOMPARE(evalJS("myObject.objectStarProperty.objectStarProperty"),
948 m_myObject->setObjectStarProperty(this);
949 QCOMPARE(evalJS("myObject.objectStarProperty != null"), sTrue);
950 QCOMPARE(evalJS("typeof myObject.objectStarProperty"), sObject);
951 QCOMPARE(evalJS("Boolean(myObject.objectStarProperty)"), sTrue);
952 QCOMPARE(evalJS("String(myObject.objectStarProperty) != 'null'"), sTrue);
955 void tst_QWebFrame::getSetDynamicProperty()
957 QFETCH(bool, garbageCollect);
959 // initially the object does not have the property
960 // In WebKit, RuntimeObjects do not inherit Object, so don't have hasOwnProperty
962 //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
963 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
965 // add a dynamic property in C++
966 QCOMPARE(m_myObject->setProperty("dynamicProperty", 123), false);
967 //QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sTrue);
968 QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
969 QCOMPARE(evalJS("myObject.dynamicProperty == 123"), sTrue);
970 if( garbageCollect ) {
972 QCOMPARE(evalJS("typeof myObject.dynamicProperty != 'undefined'"), sTrue);
975 // property change in script should be reflected in C++
976 QCOMPARE(evalJS("myObject.dynamicProperty = 'foo';"
977 "myObject.dynamicProperty"), QLatin1String("foo"));
978 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
979 if( garbageCollect ) {
981 QCOMPARE(m_myObject->property("dynamicProperty").toString(), QLatin1String("foo"));
984 // add a dynamic property in C++ to another QObject
985 QObject* propertyObject = new QObject(m_myObject);
986 QCOMPARE(m_myObject->setProperty("dynamicObjectProperty", qVariantFromValue(propertyObject)), false);
987 QCOMPARE(evalJS("typeof myObject.dynamicObjectProperty != 'undefined'"), sTrue);
988 evalJS("myObject.dynamicObjectProperty.jsProperty = 123");
989 QCOMPARE(evalJS("myObject.dynamicObjectProperty.jsProperty == 123"), sTrue);
990 if( garbageCollect ) {
992 QCOMPARE(evalJS("typeof myObject.dynamicObjectProperty != 'undefined'"), sTrue);
993 QCOMPARE(evalJS("myObject.dynamicObjectProperty.jsProperty == 123"), sTrue);
995 QCOMPARE(m_myObject->setProperty("dynamicObjectProperty", QVariant()), false);
996 delete propertyObject;
997 QCOMPARE(evalJS("typeof myObject.dynamicObjectProperty == 'undefined'"), sTrue);
999 // delete the property (XFAIL - can't delete properties)
1000 QEXPECT_FAIL("", "can't delete properties", Continue);
1001 QCOMPARE(evalJS("delete myObject.dynamicProperty"), sTrue);
1003 QCOMPARE(m_myObject->property("dynamicProperty").isValid(), false);
1004 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
1005 // QCOMPARE(evalJS("myObject.hasOwnProperty('dynamicProperty')"), sFalse);
1006 QCOMPARE(evalJS("typeof myObject.dynamicProperty"), sUndefined);
1009 evalJS("myObject.dynamicProperty = undefined");
1012 void tst_QWebFrame::getSetDynamicProperty_data()
1014 QTest::addColumn<bool>("garbageCollect");
1015 QTest::newRow("with garbageCollect") << true;
1016 QTest::newRow("without garbageCollect") << false;
1019 void tst_QWebFrame::getSetChildren()
1021 QFETCH(bool, garbageCollect);
1023 // initially the object does not have the child
1024 // (again, no hasOwnProperty)
1026 //QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
1027 QCOMPARE(evalJS("typeof myObject.child"), sUndefined);
1030 MyQObject* child = new MyQObject(m_myObject);
1031 child->setObjectName("child");
1032 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sTrue);
1033 QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
1034 evalJS("myObject.child.jsProperty = 123");
1035 QCOMPARE(evalJS("myObject.child.jsProperty == 123"), sTrue);
1037 if( garbageCollect ) {
1039 QCOMPARE(evalJS("typeof myObject.child != 'undefined'"), sTrue);
1040 QCOMPARE(evalJS("myObject.child.jsProperty == 123"), sTrue);
1044 MyQObject* grandChild = new MyQObject(child);
1045 grandChild->setObjectName("grandChild");
1046 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sTrue);
1047 QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
1048 evalJS("myObject.child.grandChild.jsProperty = 123");
1049 evalJS("myObject.child.grandChild.jsProperty = 123");
1050 if( garbageCollect ) {
1052 QCOMPARE(evalJS("typeof myObject.child.grandChild != 'undefined'"), sTrue);
1053 QCOMPARE(evalJS("myObject.child.grandChild.jsProperty == 123"), sTrue);
1056 // delete grandchild
1058 // QCOMPARE(evalJS("myObject.child.hasOwnProperty('grandChild')"), sFalse);
1059 QCOMPARE(evalJS("typeof myObject.child.grandChild == 'undefined'"), sTrue);
1063 // QCOMPARE(evalJS("myObject.hasOwnProperty('child')"), sFalse);
1064 QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
1065 if( garbageCollect ) {
1067 QCOMPARE(evalJS("typeof myObject.child == 'undefined'"), sTrue);
1072 void tst_QWebFrame::getSetChildren_data()
1074 QTest::addColumn<bool>("garbageCollect");
1075 QTest::newRow("with garbageCollect") << true;
1076 QTest::newRow("without garbageCollect") << false;
1079 Q_DECLARE_METATYPE(QVector<int>)
1080 Q_DECLARE_METATYPE(QVector<double>)
1081 Q_DECLARE_METATYPE(QVector<QString>)
1083 void tst_QWebFrame::callQtInvokable()
1085 qRegisterMetaType<QObjectList>();
1087 m_myObject->resetQtFunctionInvoked();
1088 QCOMPARE(evalJS("typeof myObject.myInvokable()"), sUndefined);
1089 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1090 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1092 // extra arguments should silently be ignored
1093 m_myObject->resetQtFunctionInvoked();
1094 QCOMPARE(evalJS("typeof myObject.myInvokable(10, 20, 30)"), sUndefined);
1095 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1096 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1098 m_myObject->resetQtFunctionInvoked();
1099 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123)"), sUndefined);
1100 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1101 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1102 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1104 m_myObject->resetQtFunctionInvoked();
1105 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg('123')"), sUndefined);
1106 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1107 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1108 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1110 m_myObject->resetQtFunctionInvoked();
1111 QCOMPARE(evalJS("typeof myObject.myInvokableWithLonglongArg(123)"), sUndefined);
1112 QCOMPARE(m_myObject->qtFunctionInvoked(), 2);
1113 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1114 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toLongLong(), qlonglong(123));
1116 m_myObject->resetQtFunctionInvoked();
1117 QCOMPARE(evalJS("typeof myObject.myInvokableWithFloatArg(123.5)"), sUndefined);
1118 QCOMPARE(m_myObject->qtFunctionInvoked(), 3);
1119 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1120 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1122 m_myObject->resetQtFunctionInvoked();
1123 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(123.5)"), sUndefined);
1124 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1125 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1126 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.5);
1128 m_myObject->resetQtFunctionInvoked();
1129 QCOMPARE(evalJS("typeof myObject.myInvokableWithDoubleArg(new Number(1234.5))"), sUndefined);
1130 QCOMPARE(m_myObject->qtFunctionInvoked(), 4);
1131 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1132 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 1234.5);
1134 m_myObject->resetQtFunctionInvoked();
1135 QCOMPARE(evalJS("typeof myObject.myInvokableWithBoolArg(new Boolean(true))"), sUndefined);
1136 QCOMPARE(m_myObject->qtFunctionInvoked(), 52);
1137 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1138 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toBool(), true);
1140 m_myObject->resetQtFunctionInvoked();
1141 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg('ciao')"), sUndefined);
1142 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1143 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1144 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("ciao"));
1146 m_myObject->resetQtFunctionInvoked();
1147 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(123)"), sUndefined);
1148 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1149 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1150 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1152 m_myObject->resetQtFunctionInvoked();
1153 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(null)"), sUndefined);
1154 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1155 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1156 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1157 QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
1159 m_myObject->resetQtFunctionInvoked();
1160 QCOMPARE(evalJS("typeof myObject.myInvokableWithStringArg(undefined)"), sUndefined);
1161 QCOMPARE(m_myObject->qtFunctionInvoked(), 5);
1162 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1163 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QString());
1164 QVERIFY(m_myObject->qtFunctionActuals().at(0).toString().isEmpty());
1166 m_myObject->resetQtFunctionInvoked();
1167 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArgs(123, 456)"), sUndefined);
1168 QCOMPARE(m_myObject->qtFunctionInvoked(), 6);
1169 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1170 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1171 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1173 m_myObject->resetQtFunctionInvoked();
1174 QCOMPARE(evalJS("myObject.myInvokableReturningInt()"), QLatin1String("123"));
1175 QCOMPARE(m_myObject->qtFunctionInvoked(), 7);
1176 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1178 m_myObject->resetQtFunctionInvoked();
1179 QCOMPARE(evalJS("myObject.myInvokableReturningLongLong()"), QLatin1String("456"));
1180 QCOMPARE(m_myObject->qtFunctionInvoked(), 39);
1181 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1183 m_myObject->resetQtFunctionInvoked();
1184 QCOMPARE(evalJS("myObject.myInvokableReturningString()"), QLatin1String("ciao"));
1185 QCOMPARE(m_myObject->qtFunctionInvoked(), 8);
1186 QCOMPARE(m_myObject->qtFunctionActuals(), QVariantList());
1188 m_myObject->resetQtFunctionInvoked();
1189 QCOMPARE(evalJS("typeof myObject.myInvokableWithIntArg(123, 456)"), sUndefined);
1190 QCOMPARE(m_myObject->qtFunctionInvoked(), 9);
1191 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1192 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1193 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toInt(), 456);
1195 m_myObject->resetQtFunctionInvoked();
1196 QCOMPARE(evalJS("typeof myObject.myInvokableWithVoidStarArg(null)"), sUndefined);
1197 QCOMPARE(m_myObject->qtFunctionInvoked(), 44);
1198 m_myObject->resetQtFunctionInvoked();
1201 QString ret = evalJS("myObject.myInvokableWithVoidStarArg(123)", type);
1202 QCOMPARE(type, sError);
1203 QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithVoidStarArg(); candidates were\n myInvokableWithVoidStarArg(void*)"));
1204 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1207 m_myObject->resetQtFunctionInvoked();
1210 QString ret = evalJS("myObject.myInvokableWithAmbiguousArg(123)", type);
1211 QCOMPARE(type, sError);
1212 QCOMPARE(ret, QLatin1String("TypeError: ambiguous call of overloaded function myInvokableWithAmbiguousArg(); candidates were\n myInvokableWithAmbiguousArg(int)\n myInvokableWithAmbiguousArg(uint)"));
1215 m_myObject->resetQtFunctionInvoked();
1218 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(123, 'hello')", type);
1219 QCOMPARE(type, sUndefined);
1220 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1221 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1222 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1223 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QLatin1String("hello"));
1226 m_myObject->resetQtFunctionInvoked();
1229 QString ret = evalJS("myObject.myInvokableWithDefaultArgs(456)", type);
1230 QCOMPARE(type, sUndefined);
1231 QCOMPARE(m_myObject->qtFunctionInvoked(), 47);
1232 QCOMPARE(m_myObject->qtFunctionActuals().size(), 2);
1233 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1234 QCOMPARE(m_myObject->qtFunctionActuals().at(1).toString(), QString());
1237 // calling function that returns (const)ref
1238 m_myObject->resetQtFunctionInvoked();
1241 QString ret = evalJS("typeof myObject.myInvokableReturningRef()");
1242 QCOMPARE(ret, sUndefined);
1243 //QVERIFY(!m_engine->hasUncaughtException());
1244 QCOMPARE(m_myObject->qtFunctionInvoked(), 48);
1247 m_myObject->resetQtFunctionInvoked();
1250 QString ret = evalJS("typeof myObject.myInvokableReturningConstRef()");
1251 QCOMPARE(ret, sUndefined);
1252 //QVERIFY(!m_engine->hasUncaughtException());
1253 QCOMPARE(m_myObject->qtFunctionInvoked(), 49);
1256 m_myObject->resetQtFunctionInvoked();
1259 QVariant ret = evalJSV("myObject.myInvokableReturningQObjectStar()", type);
1260 QCOMPARE(m_myObject->qtFunctionInvoked(), 13);
1261 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1262 QCOMPARE(type, sObject);
1263 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1266 m_myObject->resetQtFunctionInvoked();
1269 QVariant ret = evalJSV("myObject.myInvokableWithQObjectListArg([myObject])", type);
1270 QCOMPARE(m_myObject->qtFunctionInvoked(), 14);
1271 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1272 QCOMPARE(type, sArray);
1273 QCOMPARE(ret.userType(), int(QVariant::List)); // All lists get downgraded to QVariantList
1274 QVariantList vl = qvariant_cast<QVariantList>(ret);
1275 QCOMPARE(vl.count(), 1);
1278 m_myObject->resetQtFunctionInvoked();
1281 m_myObject->setVariantProperty(QVariant(123));
1282 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(myObject.variantProperty)", type);
1283 QCOMPARE(type, sNumber);
1284 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1285 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1286 QCOMPARE(m_myObject->qtFunctionActuals().at(0), m_myObject->variantProperty());
1287 QCOMPARE(ret.userType(), int(QMetaType::Double)); // all JS numbers are doubles, even though this started as an int
1288 QCOMPARE(ret.toInt(),123);
1291 m_myObject->resetQtFunctionInvoked();
1294 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(null)", type);
1295 QCOMPARE(type, sObject);
1296 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1297 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1298 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1299 QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
1302 m_myObject->resetQtFunctionInvoked();
1305 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(undefined)", type);
1306 QCOMPARE(type, sObject);
1307 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1308 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1309 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant());
1310 QVERIFY(!m_myObject->qtFunctionActuals().at(0).isValid());
1313 /* XFAIL - variant support
1314 m_myObject->resetQtFunctionInvoked();
1316 m_myObject->setVariantProperty(qVariantFromValue(QBrush()));
1317 QVariant ret = evalJS("myObject.myInvokableWithVariantArg(myObject.variantProperty)");
1318 QVERIFY(ret.isVariant());
1319 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1320 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1321 QCOMPARE(ret.toVariant(), m_myObject->qtFunctionActuals().at(0));
1322 QCOMPARE(ret.toVariant(), m_myObject->variantProperty());
1326 m_myObject->resetQtFunctionInvoked();
1329 QVariant ret = evalJSV("myObject.myInvokableWithVariantArg(123)", type);
1330 QCOMPARE(type, sNumber);
1331 QCOMPARE(m_myObject->qtFunctionInvoked(), 15);
1332 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1333 QCOMPARE(m_myObject->qtFunctionActuals().at(0), QVariant(123));
1334 QCOMPARE(ret.userType(), int(QMetaType::Double));
1335 QCOMPARE(ret.toInt(),123);
1338 m_myObject->resetQtFunctionInvoked();
1341 QVariant ret = evalJSV("myObject.myInvokableWithVariantMapArg({ a:123, b:'ciao' })", type);
1342 QCOMPARE(m_myObject->qtFunctionInvoked(), 16);
1343 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1345 QVariant v = m_myObject->qtFunctionActuals().at(0);
1346 QCOMPARE(v.userType(), int(QMetaType::QVariantMap));
1348 QVariantMap vmap = qvariant_cast<QVariantMap>(v);
1349 QCOMPARE(vmap.keys().size(), 2);
1350 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1351 QCOMPARE(vmap.value("a"), QVariant(123));
1352 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1353 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1355 QCOMPARE(type, sObject);
1357 QCOMPARE(ret.userType(), int(QMetaType::QVariantMap));
1358 vmap = qvariant_cast<QVariantMap>(ret);
1359 QCOMPARE(vmap.keys().size(), 2);
1360 QCOMPARE(vmap.keys().at(0), QLatin1String("a"));
1361 QCOMPARE(vmap.value("a"), QVariant(123));
1362 QCOMPARE(vmap.keys().at(1), QLatin1String("b"));
1363 QCOMPARE(vmap.value("b"), QVariant("ciao"));
1366 m_myObject->resetQtFunctionInvoked();
1369 QVariant ret = evalJSV("myObject.myInvokableWithListOfIntArg([1, 5])", type);
1370 QCOMPARE(m_myObject->qtFunctionInvoked(), 17);
1371 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1372 QVariant v = m_myObject->qtFunctionActuals().at(0);
1373 QCOMPARE(v.userType(), qMetaTypeId<QList<int> >());
1374 QList<int> ilst = qvariant_cast<QList<int> >(v);
1375 QCOMPARE(ilst.size(), 2);
1376 QCOMPARE(ilst.at(0), 1);
1377 QCOMPARE(ilst.at(1), 5);
1379 QCOMPARE(type, sArray);
1380 QCOMPARE(ret.userType(), int(QMetaType::QVariantList)); // ints get converted to doubles, so this is a qvariantlist
1381 QVariantList vlst = qvariant_cast<QVariantList>(ret);
1382 QCOMPARE(vlst.size(), 2);
1383 QCOMPARE(vlst.at(0).toInt(), 1);
1384 QCOMPARE(vlst.at(1).toInt(), 5);
1387 m_myObject->resetQtFunctionInvoked();
1390 QVariant ret = evalJSV("myObject.myInvokableWithQObjectStarArg(myObject)", type);
1391 QCOMPARE(m_myObject->qtFunctionInvoked(), 18);
1392 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1393 QVariant v = m_myObject->qtFunctionActuals().at(0);
1394 QCOMPARE(v.userType(), int(QMetaType::QObjectStar));
1395 QCOMPARE(qvariant_cast<QObject*>(v), (QObject*)m_myObject);
1397 QCOMPARE(ret.userType(), int(QMetaType::QObjectStar));
1398 QCOMPARE(qvariant_cast<QObject*>(ret), (QObject*)m_myObject);
1400 QCOMPARE(type, sObject);
1403 m_myObject->resetQtFunctionInvoked();
1405 // no implicit conversion from integer to QObject*
1407 evalJS("myObject.myInvokableWithQObjectStarArg(123)", type);
1408 QCOMPARE(type, sError);
1412 m_myObject->resetQtFunctionInvoked();
1414 QString fun = evalJS("myObject.myInvokableWithQBrushArg");
1415 Q_ASSERT(fun.isFunction());
1416 QColor color(10, 20, 30, 40);
1417 // QColor should be converted to a QBrush
1418 QVariant ret = fun.call(QString(), QStringList()
1419 << qScriptValueFromValue(m_engine, color));
1420 QCOMPARE(m_myObject->qtFunctionInvoked(), 19);
1421 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1422 QVariant v = m_myObject->qtFunctionActuals().at(0);
1423 QCOMPARE(v.userType(), int(QMetaType::QBrush));
1424 QCOMPARE(qvariant_cast<QColor>(v), color);
1426 QCOMPARE(qscriptvalue_cast<QColor>(ret), color);
1430 // private slots should not be part of the QObject binding
1431 QCOMPARE(evalJS("typeof myObject.myPrivateSlot"), sUndefined);
1433 // protected slots should be fine
1434 m_myObject->resetQtFunctionInvoked();
1435 evalJS("myObject.myProtectedSlot()");
1436 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1438 // call with too few arguments
1441 QString ret = evalJS("myObject.myInvokableWithIntArg()", type);
1442 QCOMPARE(type, sError);
1443 QCOMPARE(ret, QLatin1String("SyntaxError: too few arguments in call to myInvokableWithIntArg(); candidates are\n myInvokableWithIntArg(int,int)\n myInvokableWithIntArg(int)"));
1446 // call function where not all types have been registered
1447 m_myObject->resetQtFunctionInvoked();
1450 QString ret = evalJS("myObject.myInvokableWithBrushStyleArg(0)", type);
1451 QCOMPARE(type, sError);
1452 QCOMPARE(ret, QLatin1String("TypeError: cannot call myInvokableWithBrushStyleArg(): unknown type `Qt::BrushStyle'"));
1453 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1456 // call function with incompatible argument type
1457 m_myObject->resetQtFunctionInvoked();
1460 QString ret = evalJS("myObject.myInvokableWithQBrushArg(null)", type);
1461 QCOMPARE(type, sError);
1462 QCOMPARE(ret, QLatin1String("TypeError: incompatible type of argument(s) in call to myInvokableWithQBrushArg(); candidates were\n myInvokableWithQBrushArg(QBrush)"));
1463 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1467 void tst_QWebFrame::connectAndDisconnect()
1469 // connect(function)
1470 QCOMPARE(evalJS("typeof myObject.mySignal"), sFunction);
1471 QCOMPARE(evalJS("typeof myObject.mySignal.connect"), sFunction);
1472 QCOMPARE(evalJS("typeof myObject.mySignal.disconnect"), sFunction);
1476 evalJS("myObject.mySignal.connect(123)", type);
1477 QCOMPARE(type, sError);
1480 evalJS("myHandler = function() { window.gotSignal = true; window.signalArgs = arguments; window.slotThisObject = this; window.signalSender = __qt_sender__; }");
1482 QCOMPARE(evalJS("myObject.mySignal.connect(myHandler)"), sUndefined);
1484 evalJS("gotSignal = false");
1485 evalJS("myObject.mySignal()");
1486 QCOMPARE(evalJS("gotSignal"), sTrue);
1487 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1488 QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1489 QCOMPARE(evalJS("slotThisObject == window"), sTrue);
1491 evalJS("gotSignal = false");
1492 m_myObject->emitMySignal();
1493 QCOMPARE(evalJS("gotSignal"), sTrue);
1494 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1496 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myHandler)"), sUndefined);
1498 evalJS("gotSignal = false");
1499 m_myObject->emitMySignalWithIntArg(123);
1500 QCOMPARE(evalJS("gotSignal"), sTrue);
1501 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1502 QCOMPARE(evalJS("signalArgs[0] == 123.0"), sTrue);
1504 QCOMPARE(evalJS("myObject.mySignal.disconnect(myHandler)"), sUndefined);
1507 evalJS("myObject.mySignal.disconnect(myHandler)", type);
1508 QCOMPARE(type, sError);
1511 evalJS("gotSignal = false");
1512 QCOMPARE(evalJS("myObject.mySignal2.connect(myHandler)"), sUndefined);
1513 m_myObject->emitMySignal2(true);
1514 QCOMPARE(evalJS("gotSignal"), sTrue);
1515 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1516 QCOMPARE(evalJS("signalArgs[0]"), sTrue);
1518 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myHandler)"), sUndefined);
1520 QCOMPARE(evalJS("typeof myObject['mySignal2()']"), sFunction);
1521 QCOMPARE(evalJS("typeof myObject['mySignal2()'].connect"), sFunction);
1522 QCOMPARE(evalJS("typeof myObject['mySignal2()'].disconnect"), sFunction);
1524 QCOMPARE(evalJS("myObject['mySignal2()'].connect(myHandler)"), sUndefined);
1526 evalJS("gotSignal = false");
1527 m_myObject->emitMySignal2();
1528 QCOMPARE(evalJS("gotSignal"), sTrue);
1530 QCOMPARE(evalJS("myObject['mySignal2()'].disconnect(myHandler)"), sUndefined);
1532 // connect(object, function)
1533 evalJS("otherObject = { name:'foo' }");
1534 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1535 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1536 evalJS("gotSignal = false");
1537 m_myObject->emitMySignal();
1538 QCOMPARE(evalJS("gotSignal"), sFalse);
1542 evalJS("myObject.mySignal.disconnect(otherObject, myHandler)", type);
1543 QCOMPARE(type, sError);
1546 QCOMPARE(evalJS("myObject.mySignal.connect(otherObject, myHandler)"), sUndefined);
1547 evalJS("gotSignal = false");
1548 m_myObject->emitMySignal();
1549 QCOMPARE(evalJS("gotSignal"), sTrue);
1550 QCOMPARE(evalJS("signalArgs.length == 0"), sTrue);
1551 QCOMPARE(evalJS("slotThisObject"),evalJS("otherObject"));
1552 QCOMPARE(evalJS("signalSender"),evalJS("myObject"));
1553 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("foo"));
1554 QCOMPARE(evalJS("myObject.mySignal.disconnect(otherObject, myHandler)"), sUndefined);
1556 evalJS("yetAnotherObject = { name:'bar', func : function() { } }");
1557 QCOMPARE(evalJS("myObject.mySignal2.connect(yetAnotherObject, myHandler)"), sUndefined);
1558 evalJS("gotSignal = false");
1559 m_myObject->emitMySignal2(true);
1560 QCOMPARE(evalJS("gotSignal"), sTrue);
1561 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1562 QCOMPARE(evalJS("slotThisObject == yetAnotherObject"), sTrue);
1563 QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1564 QCOMPARE(evalJS("slotThisObject.name"), QLatin1String("bar"));
1565 QCOMPARE(evalJS("myObject.mySignal2.disconnect(yetAnotherObject, myHandler)"), sUndefined);
1567 QCOMPARE(evalJS("myObject.mySignal2.connect(myObject, myHandler)"), sUndefined);
1568 evalJS("gotSignal = false");
1569 m_myObject->emitMySignal2(true);
1570 QCOMPARE(evalJS("gotSignal"), sTrue);
1571 QCOMPARE(evalJS("signalArgs.length == 1"), sTrue);
1572 QCOMPARE(evalJS("slotThisObject == myObject"), sTrue);
1573 QCOMPARE(evalJS("signalSender == myObject"), sTrue);
1574 QCOMPARE(evalJS("myObject.mySignal2.disconnect(myObject, myHandler)"), sUndefined);
1576 // connect(obj, string)
1577 QCOMPARE(evalJS("myObject.mySignal.connect(yetAnotherObject, 'func')"), sUndefined);
1578 QCOMPARE(evalJS("myObject.mySignal.connect(myObject, 'mySlot')"), sUndefined);
1579 QCOMPARE(evalJS("myObject.mySignal.disconnect(yetAnotherObject, 'func')"), sUndefined);
1580 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject, 'mySlot')"), sUndefined);
1582 // check that emitting signals from script works
1585 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1586 m_myObject->resetQtFunctionInvoked();
1587 QCOMPARE(evalJS("myObject.mySignal()"), sUndefined);
1588 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1589 QCOMPARE(evalJS("myObject.mySignal.disconnect(myObject.mySlot)"), sUndefined);
1592 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithIntArg)"), sUndefined);
1593 m_myObject->resetQtFunctionInvoked();
1594 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1595 QCOMPARE(m_myObject->qtFunctionInvoked(), 21);
1596 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1597 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1598 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithIntArg)"), sUndefined);
1600 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithDoubleArg)"), sUndefined);
1601 m_myObject->resetQtFunctionInvoked();
1602 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1603 QCOMPARE(m_myObject->qtFunctionInvoked(), 22);
1604 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1605 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDouble(), 123.0);
1606 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithDoubleArg)"), sUndefined);
1608 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.mySlotWithStringArg)"), sUndefined);
1609 m_myObject->resetQtFunctionInvoked();
1610 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1611 QCOMPARE(m_myObject->qtFunctionInvoked(), 23);
1612 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1613 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toString(), QLatin1String("123"));
1614 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.mySlotWithStringArg)"), sUndefined);
1616 // connecting to overloaded slot
1617 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject.myOverloadedSlot)"), sUndefined);
1618 m_myObject->resetQtFunctionInvoked();
1619 QCOMPARE(evalJS("myObject.mySignalWithIntArg(123)"), sUndefined);
1620 QCOMPARE(m_myObject->qtFunctionInvoked(), 26); // double overload
1621 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1622 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 123);
1623 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject.myOverloadedSlot)"), sUndefined);
1625 QCOMPARE(evalJS("myObject.mySignalWithIntArg.connect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1626 m_myObject->resetQtFunctionInvoked();
1627 QCOMPARE(evalJS("myObject.mySignalWithIntArg(456)"), sUndefined);
1628 QCOMPARE(m_myObject->qtFunctionInvoked(), 28); // int overload
1629 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1630 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), 456);
1631 QCOMPARE(evalJS("myObject.mySignalWithIntArg.disconnect(myObject['myOverloadedSlot(int)'])"), sUndefined);
1635 // ### QtScript adds .connect to all functions, WebKit does only to signals/slots
1637 QString ret = evalJS("(function() { }).connect()", type);
1638 QCOMPARE(type, sError);
1639 QCOMPARE(ret, QLatin1String("TypeError: Result of expression '(function() { }).connect' [undefined] is not a function."));
1643 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect()", type);
1644 QCOMPARE(type, sError);
1645 QCOMPARE(ret, QLatin1String("TypeError: Result of expression 'o.connect' [undefined] is not a function."));
1650 QString ret = evalJS("(function() { }).connect(123)", type);
1651 QCOMPARE(type, sError);
1652 QCOMPARE(ret, QLatin1String("TypeError: Result of expression '(function() { }).connect' [undefined] is not a function."));
1656 QString ret = evalJS("var o = { }; o.connect = Function.prototype.connect; o.connect(123)", type);
1657 QCOMPARE(type, sError);
1658 QCOMPARE(ret, QLatin1String("TypeError: Result of expression 'o.connect' [undefined] is not a function."));
1663 QString ret = evalJS("myObject.myInvokable.connect(123)", type);
1664 QCOMPARE(type, sError);
1665 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1669 QString ret = evalJS("myObject.myInvokable.connect(function() { })", type);
1670 QCOMPARE(type, sError);
1671 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: MyQObject::myInvokable() is not a signal"));
1676 QString ret = evalJS("myObject.mySignal.connect(123)", type);
1677 QCOMPARE(type, sError);
1678 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.connect: target is not a function"));
1683 QString ret = evalJS("myObject.mySignal.disconnect()", type);
1684 QCOMPARE(type, sError);
1685 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1689 QString ret = evalJS("var o = { }; o.disconnect = myObject.mySignal.disconnect; o.disconnect()", type);
1690 QCOMPARE(type, sError);
1691 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: no arguments given"));
1694 /* XFAIL - Function.prototype doesn't get connect/disconnect, just signals/slots
1697 QString ret = evalJS("(function() { }).disconnect(123)", type);
1698 QCOMPARE(type, sError);
1699 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: this object is not a signal"));
1705 QString ret = evalJS("var o = { }; o.disconnect = myObject.myInvokable.disconnect; o.disconnect(123)", type);
1706 QCOMPARE(type, sError);
1707 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1712 QString ret = evalJS("myObject.myInvokable.disconnect(123)", type);
1713 QCOMPARE(type, sError);
1714 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1718 QString ret = evalJS("myObject.myInvokable.disconnect(function() { })", type);
1719 QCOMPARE(type, sError);
1720 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: MyQObject::myInvokable() is not a signal"));
1725 QString ret = evalJS("myObject.mySignal.disconnect(123)", type);
1726 QCOMPARE(type, sError);
1727 QCOMPARE(ret, QLatin1String("TypeError: QtMetaMethod.disconnect: target is not a function"));
1732 QString ret = evalJS("myObject.mySignal.disconnect(function() { })", type);
1733 QCOMPARE(type, sError);
1734 QCOMPARE(ret, QLatin1String("Error: QtMetaMethod.disconnect: failed to disconnect from MyQObject::mySignal()"));
1737 // when the wrapper dies, the connection stays alive
1738 QCOMPARE(evalJS("myObject.mySignal.connect(myObject.mySlot)"), sUndefined);
1739 m_myObject->resetQtFunctionInvoked();
1740 m_myObject->emitMySignal();
1741 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1742 evalJS("myObject = null");
1744 m_myObject->resetQtFunctionInvoked();
1745 m_myObject->emitMySignal();
1746 QCOMPARE(m_myObject->qtFunctionInvoked(), 20);
1749 void tst_QWebFrame::classEnums()
1751 // We don't do the meta thing currently, unfortunately!!!
1753 QString myClass = m_engine->newQMetaObject(m_myObject->metaObject(), m_engine->undefinedValue());
1754 m_engine->globalObject().setProperty("MyQObject", myClass);
1756 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.FooPolicy").toInt()),
1757 MyQObject::FooPolicy);
1758 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BarPolicy").toInt()),
1759 MyQObject::BarPolicy);
1760 QCOMPARE(static_cast<MyQObject::Policy>(evalJS("MyQObject.BazPolicy").toInt()),
1761 MyQObject::BazPolicy);
1763 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.FooStrategy").toInt()),
1764 MyQObject::FooStrategy);
1765 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BarStrategy").toInt()),
1766 MyQObject::BarStrategy);
1767 QCOMPARE(static_cast<MyQObject::Strategy>(evalJS("MyQObject.BazStrategy").toInt()),
1768 MyQObject::BazStrategy);
1770 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.NoAbility").toInt()),
1771 MyQObject::NoAbility);
1772 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.FooAbility").toInt()),
1773 MyQObject::FooAbility);
1774 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BarAbility").toInt()),
1775 MyQObject::BarAbility);
1776 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.BazAbility").toInt()),
1777 MyQObject::BazAbility);
1778 QCOMPARE(MyQObject::Ability(evalJS("MyQObject.AllAbility").toInt()),
1779 MyQObject::AllAbility);
1781 // enums from Qt are inherited through prototype
1782 QCOMPARE(static_cast<Qt::FocusPolicy>(evalJS("MyQObject.StrongFocus").toInt()),
1784 QCOMPARE(static_cast<Qt::Key>(evalJS("MyQObject.Key_Left").toInt()),
1787 QCOMPARE(evalJS("MyQObject.className()"), QLatin1String("MyQObject"));
1789 qRegisterMetaType<MyQObject::Policy>("Policy");
1791 m_myObject->resetQtFunctionInvoked();
1792 QCOMPARE(evalJS("myObject.myInvokableWithEnumArg(MyQObject.BazPolicy)"), sUndefined);
1793 QCOMPARE(m_myObject->qtFunctionInvoked(), 10);
1794 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1795 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1797 m_myObject->resetQtFunctionInvoked();
1798 QCOMPARE(evalJS("myObject.myInvokableWithQualifiedEnumArg(MyQObject.BazPolicy)"), sUndefined);
1799 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
1800 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
1801 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toInt(), int(MyQObject::BazPolicy));
1803 m_myObject->resetQtFunctionInvoked();
1805 QVariant ret = evalJS("myObject.myInvokableReturningEnum()");
1806 QCOMPARE(m_myObject->qtFunctionInvoked(), 37);
1807 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1808 QCOMPARE(ret.isVariant());
1810 m_myObject->resetQtFunctionInvoked();
1812 QVariant ret = evalJS("myObject.myInvokableReturningQualifiedEnum()");
1813 QCOMPARE(m_myObject->qtFunctionInvoked(), 38);
1814 QCOMPARE(m_myObject->qtFunctionActuals().size(), 0);
1815 QCOMPARE(ret.isNumber());
1820 void tst_QWebFrame::classConstructor()
1823 QString myClass = qScriptValueFromQMetaObject<MyQObject>(m_engine);
1824 m_engine->globalObject().setProperty("MyQObject", myClass);
1826 QString myObj = evalJS("myObj = MyQObject()");
1827 QObject* qobj = myObj.toQObject();
1829 QCOMPARE(qobj->metaObject()->className(), "MyQObject");
1830 QCOMPARE(qobj->parent(), (QObject*)0);
1832 QString qobjectClass = qScriptValueFromQMetaObject<QObject>(m_engine);
1833 m_engine->globalObject().setProperty("QObject", qobjectClass);
1835 QString otherObj = evalJS("otherObj = QObject(myObj)");
1836 QObject* qqobj = otherObj.toQObject();
1837 QVERIFY(qqobj != 0);
1838 QCOMPARE(qqobj->metaObject()->className(), "QObject");
1839 QCOMPARE(qqobj->parent(), qobj);
1845 void tst_QWebFrame::overrideInvokable()
1847 m_myObject->resetQtFunctionInvoked();
1848 QCOMPARE(evalJS("myObject.myInvokable()"), sUndefined);
1849 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1851 /* XFAIL - can't write to functions with RuntimeObject
1852 m_myObject->resetQtFunctionInvoked();
1853 evalJS("myObject.myInvokable = function() { window.a = 123; }");
1854 evalJS("myObject.myInvokable()");
1855 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1856 QCOMPARE(evalJS("window.a").toDouble(), 123.0);
1858 evalJS("myObject.myInvokable = function() { window.a = 456; }");
1859 evalJS("myObject.myInvokable()");
1860 QCOMPARE(m_myObject->qtFunctionInvoked(), -1);
1861 QCOMPARE(evalJS("window.a").toDouble(), 456.0);
1864 evalJS("delete myObject.myInvokable");
1865 evalJS("myObject.myInvokable()");
1866 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1869 m_myObject->resetQtFunctionInvoked();
1870 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1871 evalJS("myObject.myInvokable(123)");
1872 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1875 evalJS("delete myObject.myInvokable");
1876 m_myObject->resetQtFunctionInvoked();
1877 // this form (with the '()') is read-only
1878 evalJS("myObject['myInvokable()'] = function() { window.a = 123; }");
1879 evalJS("myObject.myInvokable()");
1880 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1883 void tst_QWebFrame::transferInvokable()
1885 /* XFAIL - can't put to functions with RuntimeObject
1886 m_myObject->resetQtFunctionInvoked();
1887 evalJS("myObject.foozball = myObject.myInvokable");
1888 evalJS("myObject.foozball()");
1889 QCOMPARE(m_myObject->qtFunctionInvoked(), 0);
1890 m_myObject->resetQtFunctionInvoked();
1891 evalJS("myObject.foozball = myObject.myInvokableWithIntArg");
1892 evalJS("myObject.foozball(123)");
1893 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1894 m_myObject->resetQtFunctionInvoked();
1895 evalJS("myObject.myInvokable = myObject.myInvokableWithIntArg");
1896 evalJS("myObject.myInvokable(123)");
1897 QCOMPARE(m_myObject->qtFunctionInvoked(), 1);
1899 MyOtherQObject other;
1900 m_page->mainFrame()->addToJSWindowObject("myOtherObject", &other);
1901 evalJS("myOtherObject.foo = myObject.foozball");
1902 other.resetQtFunctionInvoked();
1903 evalJS("myOtherObject.foo(456)");
1904 QCOMPARE(other.qtFunctionInvoked(), 1);
1908 void tst_QWebFrame::findChild()
1911 QObject* child = new QObject(m_myObject);
1912 child->setObjectName(QLatin1String("myChildObject"));
1915 QString result = evalJS("myObject.findChild('noSuchChild')");
1916 QCOMPARE(result.isNull());
1920 QString result = evalJS("myObject.findChild('myChildObject')");
1921 QCOMPARE(result.isQObject());
1922 QCOMPARE(result.toQObject(), child);
1929 void tst_QWebFrame::findChildren()
1932 QObject* child = new QObject(m_myObject);
1933 child->setObjectName(QLatin1String("myChildObject"));
1936 QString result = evalJS("myObject.findChildren('noSuchChild')");
1937 QCOMPARE(result.isArray());
1938 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 0.0);
1942 QString result = evalJS("myObject.findChildren('myChildObject')");
1943 QCOMPARE(result.isArray());
1944 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1945 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1948 QObject* namelessChild = new QObject(m_myObject);
1951 QString result = evalJS("myObject.findChildren('myChildObject')");
1952 QCOMPARE(result.isArray());
1953 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1954 QCOMPARE(result.property(QLatin1String("0")).toQObject(), child);
1957 QObject* anotherChild = new QObject(m_myObject);
1958 anotherChild->setObjectName(QLatin1String("anotherChildObject"));
1961 QString result = evalJS("myObject.findChildren('anotherChildObject')");
1962 QCOMPARE(result.isArray());
1963 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 1.0);
1964 QCOMPARE(result.property(QLatin1String("0")).toQObject(), anotherChild);
1967 anotherChild->setObjectName(QLatin1String("myChildObject"));
1969 QString result = evalJS("myObject.findChildren('myChildObject')");
1970 QCOMPARE(result.isArray());
1971 QCOMPARE(result.property(QLatin1String("length")).toDouble(), 2.0);
1972 QObject* o1 = result.property(QLatin1String("0")).toQObject();
1973 QObject* o2 = result.property(QLatin1String("1")).toQObject();
1975 QCOMPARE(o1, anotherChild);
1976 QCOMPARE(o2, child);
1978 QCOMPARE(o1, child);
1979 QCOMPARE(o2, anotherChild);
1985 QString result = evalJS("myObject.findChildren()");
1986 QVERIFY(result.isArray());
1988 QCOMPARE(result.property("length"), QLatin1String(count);
1989 for (int i = 0; i < 3; ++i) {
1990 QObject* o = result.property(i).toQObject();
1991 if (o == namelessChild || o == child || o == anotherChild)
1994 QVERIFY(count == 0);
1997 delete anotherChild;
1998 delete namelessChild;
2003 void tst_QWebFrame::overloadedSlots()
2005 // should pick myOverloadedSlot(double)
2006 m_myObject->resetQtFunctionInvoked();
2007 evalJS("myObject.myOverloadedSlot(10)");
2008 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
2010 // should pick myOverloadedSlot(double)
2011 m_myObject->resetQtFunctionInvoked();
2012 evalJS("myObject.myOverloadedSlot(10.0)");
2013 QCOMPARE(m_myObject->qtFunctionInvoked(), 26);
2015 // should pick myOverloadedSlot(QString)
2016 m_myObject->resetQtFunctionInvoked();
2017 evalJS("myObject.myOverloadedSlot('10')");
2018 QCOMPARE(m_myObject->qtFunctionInvoked(), 29);
2020 // should pick myOverloadedSlot(bool)
2021 m_myObject->resetQtFunctionInvoked();
2022 evalJS("myObject.myOverloadedSlot(true)");
2023 QCOMPARE(m_myObject->qtFunctionInvoked(), 25);
2025 // should pick myOverloadedSlot(QDateTime)
2026 m_myObject->resetQtFunctionInvoked();
2027 evalJS("myObject.myOverloadedSlot(new Date())");
2028 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2030 // should pick myOverloadedSlot(QRegExp)
2031 m_myObject->resetQtFunctionInvoked();
2032 evalJS("myObject.myOverloadedSlot(new RegExp())");
2033 QCOMPARE(m_myObject->qtFunctionInvoked(), 34);
2035 // should pick myOverloadedSlot(QVariant)
2037 m_myObject->resetQtFunctionInvoked();
2038 QString f = evalJS("myObject.myOverloadedSlot");
2039 f.call(QString(), QStringList() << m_engine->newVariant(QVariant("ciao")));
2040 QCOMPARE(m_myObject->qtFunctionInvoked(), 35);
2043 // should pick myOverloadedSlot(QRegExp)
2044 m_myObject->resetQtFunctionInvoked();
2045 evalJS("myObject.myOverloadedSlot(document.body)");
2046 QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=37319", Continue);
2047 QCOMPARE(m_myObject->qtFunctionInvoked(), 36);
2049 // should pick myOverloadedSlot(QObject*)
2050 m_myObject->resetQtFunctionInvoked();
2051 evalJS("myObject.myOverloadedSlot(myObject)");
2052 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
2054 // should pick myOverloadedSlot(QObject*)
2055 m_myObject->resetQtFunctionInvoked();
2056 evalJS("myObject.myOverloadedSlot(null)");
2057 QCOMPARE(m_myObject->qtFunctionInvoked(), 41);
2059 // should pick myOverloadedSlot(QStringList)
2060 m_myObject->resetQtFunctionInvoked();
2061 evalJS("myObject.myOverloadedSlot(['hello'])");
2062 QCOMPARE(m_myObject->qtFunctionInvoked(), 42);
2065 void tst_QWebFrame::enumerate_data()
2067 QTest::addColumn<QStringList>("expectedNames");
2069 QTest::newRow("enumerate all")
2071 // meta-object-defined properties:
2075 << "p1" << "p2" << "p4" << "p6"
2076 // dynamic properties
2077 << "dp1" << "dp2" << "dp3"
2079 << "destroyed(QObject*)" << "destroyed()"
2081 // not included because it's private:
2082 // << "_q_reregisterTimers(void*)"
2086 << "mySlot()" << "myOtherSlot()");
2089 void tst_QWebFrame::enumerate()
2091 QFETCH(QStringList, expectedNames);
2093 MyEnumTestQObject enumQObject;
2094 // give it some dynamic properties
2095 enumQObject.setProperty("dp1", "dp1");
2096 enumQObject.setProperty("dp2", "dp2");
2097 enumQObject.setProperty("dp3", "dp3");
2098 m_page->mainFrame()->addToJavaScriptWindowObject("myEnumObject", &enumQObject);
2100 // enumerate in script
2102 evalJS("var enumeratedProperties = []");
2103 evalJS("for (var p in myEnumObject) { enumeratedProperties.push(p); }");
2104 QStringList result = evalJSV("enumeratedProperties").toStringList();
2105 QCOMPARE(result.size(), expectedNames.size());
2106 for (int i = 0; i < expectedNames.size(); ++i)
2107 QCOMPARE(result.at(i), expectedNames.at(i));
2111 void tst_QWebFrame::objectDeleted()
2113 MyQObject* qobj = new MyQObject();
2114 m_page->mainFrame()->addToJavaScriptWindowObject("bar", qobj);
2115 evalJS("bar.objectName = 'foo';");
2116 QCOMPARE(qobj->objectName(), QLatin1String("foo"));
2117 evalJS("bar.intProperty = 123;");
2118 QCOMPARE(qobj->intProperty(), 123);
2119 qobj->resetQtFunctionInvoked();
2120 evalJS("bar.myInvokable.call(bar);");
2121 QCOMPARE(qobj->qtFunctionInvoked(), 0);
2123 // do this, to ensure that we cache that it implements call
2126 // now delete the object
2129 QCOMPARE(evalJS("typeof bar"), sObject);
2131 // any attempt to access properties of the object should result in an exception
2134 QString ret = evalJS("bar.objectName", type);
2135 QCOMPARE(type, sError);
2136 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
2140 QString ret = evalJS("bar.objectName = 'foo'", type);
2141 QCOMPARE(type, sError);
2142 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
2145 // myInvokable is stored in member table (since we've accessed it before deletion)
2148 evalJS("bar.myInvokable", type);
2149 QCOMPARE(type, sFunction);
2154 QString ret = evalJS("bar.myInvokable.call(bar);", type);
2155 ret = evalJS("bar.myInvokable(bar)", type);
2156 QCOMPARE(type, sError);
2157 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
2159 // myInvokableWithIntArg is not stored in member table (since we've not accessed it)
2162 QString ret = evalJS("bar.myInvokableWithIntArg", type);
2163 QCOMPARE(type, sError);
2164 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
2167 // access from script
2168 evalJS("window.o = bar;");
2171 QString ret = evalJS("o.objectName", type);
2172 QCOMPARE(type, sError);
2173 QCOMPARE(ret, QLatin1String("Error: cannot access member `objectName' of deleted QObject"));
2177 QString ret = evalJS("o.myInvokable()", type);
2178 QCOMPARE(type, sError);
2179 QCOMPARE(ret, QLatin1String("Error: cannot call function of deleted QObject"));
2183 QString ret = evalJS("o.myInvokableWithIntArg(10)", type);
2184 QCOMPARE(type, sError);
2185 QCOMPARE(ret, QLatin1String("Error: cannot access member `myInvokableWithIntArg' of deleted QObject"));
2189 void tst_QWebFrame::typeConversion()
2191 m_myObject->resetQtFunctionInvoked();
2193 QDateTime localdt(QDate(2008,1,18), QTime(12,31,0));
2194 QDateTime utclocaldt = localdt.toUTC();
2195 QDateTime utcdt(QDate(2008,1,18), QTime(12,31,0), Qt::UTC);
2197 // Dates in JS (default to local)
2198 evalJS("myObject.myOverloadedSlot(new Date(2008,0,18,12,31,0))");
2199 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2200 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2201 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utclocaldt);
2203 m_myObject->resetQtFunctionInvoked();
2204 evalJS("myObject.myOverloadedSlot(new Date(Date.UTC(2008,0,18,12,31,0)))");
2205 QCOMPARE(m_myObject->qtFunctionInvoked(), 32);
2206 QCOMPARE(m_myObject->qtFunctionActuals().size(), 1);
2207 QCOMPARE(m_myObject->qtFunctionActuals().at(0).toDateTime().toUTC(), utcdt);
2209 // Pushing QDateTimes into JS
2211 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(2008,0,18,12,31,0))?true:false;}");
2212 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
2213 m_myObject->emitMySignalWithDateTimeArg(localdt);
2214 QCOMPARE(evalJS("window.__date_equals"), sTrue);
2215 evalJS("delete window.__date_equals");
2216 m_myObject->emitMySignalWithDateTimeArg(utclocaldt);
2217 QCOMPARE(evalJS("window.__date_equals"), sTrue);
2218 evalJS("delete window.__date_equals");
2219 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
2222 evalJS("function checkDate(d) {window.__date_equals = (d.toString() == new Date(Date.UTC(2008,0,18,12,31,0)))?true:false; }");
2223 evalJS("myObject.mySignalWithDateTimeArg.connect(checkDate)");
2224 m_myObject->emitMySignalWithDateTimeArg(utcdt);
2225 QCOMPARE(evalJS("window.__date_equals"), sTrue);
2226 evalJS("delete window.__date_equals");
2227 evalJS("myObject.mySignalWithDateTimeArg.disconnect(checkDate); delete checkDate;");
2232 class StringListTestObject : public QObject {
2235 QVariant stringList()
2237 return QStringList() << "Q" << "t";
2241 void tst_QWebFrame::arrayObjectEnumerable()
2244 QWebFrame* frame = page.mainFrame();
2245 QObject* qobject = new StringListTestObject();
2246 frame->addToJavaScriptWindowObject("test", qobject, QScriptEngine::ScriptOwnership);
2248 const QString script("var stringArray = test.stringList();"
2250 "for (var i in stringArray) {"
2251 " result += stringArray[i];"
2254 QCOMPARE(frame->evaluateJavaScript(script).toString(), QString::fromLatin1("Qt"));
2257 void tst_QWebFrame::symmetricUrl()
2259 QVERIFY(m_view->url().isEmpty());
2261 QCOMPARE(m_view->history()->count(), 0);
2263 QUrl dataUrl("data:text/html,<h1>Test");
2265 m_view->setUrl(dataUrl);
2266 QCOMPARE(m_view->url(), dataUrl);
2267 QCOMPARE(m_view->history()->count(), 0);
2269 // loading is _not_ immediate, so the text isn't set just yet.
2270 QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty());
2272 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2274 QCOMPARE(m_view->history()->count(), 1);
2275 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test"));
2277 QUrl dataUrl2("data:text/html,<h1>Test2");
2278 QUrl dataUrl3("data:text/html,<h1>Test3");
2280 m_view->setUrl(dataUrl2);
2281 m_view->setUrl(dataUrl3);
2283 QCOMPARE(m_view->url(), dataUrl3);
2285 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2287 QCOMPARE(m_view->history()->count(), 2);
2289 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3"));
2292 void tst_QWebFrame::progressSignal()
2294 QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int)));
2296 QUrl dataUrl("data:text/html,<h1>Test");
2297 m_view->setUrl(dataUrl);
2299 ::waitForSignal(m_view, SIGNAL(loadFinished(bool)));
2301 QVERIFY(progressSpy.size() >= 2);
2303 // WebKit defines initialProgressValue as 10%, not 0%
2304 QCOMPARE(progressSpy.first().first().toInt(), 10);
2306 // But we always end at 100%
2307 QCOMPARE(progressSpy.last().first().toInt(), 100);
2310 void tst_QWebFrame::urlChange()
2312 QSignalSpy urlSpy(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
2314 QUrl dataUrl("data:text/html,<h1>Test");
2315 m_view->setUrl(dataUrl);
2317 ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
2319 QCOMPARE(urlSpy.size(), 1);
2321 QUrl dataUrl2("data:text/html,<html><head><title>title</title></head><body><h1>Test</body></html>");
2322 m_view->setUrl(dataUrl2);
2324 ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl)));
2326 QCOMPARE(urlSpy.size(), 2);
2330 void tst_QWebFrame::domCycles()
2332 m_view->setHtml("<html><body>");
2333 QVariant v = m_page->mainFrame()->evaluateJavaScript("document");
2334 QVERIFY(v.type() == QVariant::Map);
2337 class FakeReply : public QNetworkReply {
2341 FakeReply(const QNetworkRequest& request, QObject* parent = 0)
2342 : QNetworkReply(parent)
2344 setOperation(QNetworkAccessManager::GetOperation);
2345 setRequest(request);
2346 if (request.url() == QUrl("qrc:/test1.html")) {
2347 setHeader(QNetworkRequest::LocationHeader, QString("qrc:/test2.html"));
2348 setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html"));
2350 #ifndef QT_NO_OPENSSL
2351 else if (request.url() == QUrl("qrc:/fake-ssl-error.html"))
2352 setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error !")); // force a ssl error
2354 else if (request.url() == QUrl("http://abcdef.abcdef/"))
2355 setError(QNetworkReply::HostNotFoundError, tr("Invalid URL"));
2357 open(QIODevice::ReadOnly);
2358 QTimer::singleShot(0, this, SLOT(timeout()));
2364 virtual void abort() {}
2365 virtual void close() {}
2368 qint64 readData(char*, qint64)
2376 if (request().url() == QUrl("qrc://test1.html"))
2377 emit error(this->error());
2378 else if (request().url() == QUrl("http://abcdef.abcdef/"))
2379 emit metaDataChanged();
2380 #ifndef QT_NO_OPENSSL
2381 else if (request().url() == QUrl("qrc:/fake-ssl-error.html"))
2390 class FakeNetworkManager : public QNetworkAccessManager {
2394 FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { }
2397 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData)
2399 QString url = request.url().toString();
2400 if (op == QNetworkAccessManager::GetOperation) {
2401 if (url == "qrc:/test1.html" || url == "http://abcdef.abcdef/")
2402 return new FakeReply(request, this);
2403 #ifndef QT_NO_OPENSSL
2404 else if (url == "qrc:/fake-ssl-error.html") {
2405 FakeReply* reply = new FakeReply(request, this);
2406 QList<QSslError> errors;
2407 emit sslErrors(reply, errors << QSslError(QSslError::UnspecifiedError));
2413 return QNetworkAccessManager::createRequest(op, request, outgoingData);
2417 void tst_QWebFrame::requestedUrl()
2420 QWebFrame* frame = page.mainFrame();
2422 // in few seconds, the image should be completely loaded
2423 QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
2424 FakeNetworkManager* networkManager = new FakeNetworkManager(&page);
2425 page.setNetworkAccessManager(networkManager);
2427 frame->setUrl(QUrl("qrc:/test1.html"));
2428 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2429 QCOMPARE(spy.count(), 1);
2430 QCOMPARE(frame->requestedUrl(), QUrl("qrc:/test1.html"));
2431 QCOMPARE(frame->url(), QUrl("qrc:/test2.html"));
2433 frame->setUrl(QUrl("qrc:/non-existent.html"));
2434 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2435 QCOMPARE(spy.count(), 2);
2436 QCOMPARE(frame->requestedUrl(), QUrl("qrc:/non-existent.html"));
2437 QCOMPARE(frame->url(), QUrl("qrc:/non-existent.html"));
2439 frame->setUrl(QUrl("http://abcdef.abcdef"));
2440 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2441 QCOMPARE(spy.count(), 3);
2442 QCOMPARE(frame->requestedUrl(), QUrl("http://abcdef.abcdef/"));
2443 QCOMPARE(frame->url(), QUrl("http://abcdef.abcdef/"));
2445 #ifndef QT_NO_OPENSSL
2446 qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
2447 qRegisterMetaType<QNetworkReply* >("QNetworkReply*");
2449 QSignalSpy spy2(page.networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)));
2450 frame->setUrl(QUrl("qrc:/fake-ssl-error.html"));
2451 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2452 QCOMPARE(spy2.count(), 1);
2453 QCOMPARE(frame->requestedUrl(), QUrl("qrc:/fake-ssl-error.html"));
2454 QCOMPARE(frame->url(), QUrl("qrc:/fake-ssl-error.html"));
2458 void tst_QWebFrame::javaScriptWindowObjectCleared_data()
2460 QTest::addColumn<QString>("html");
2461 QTest::addColumn<int>("signalCount");
2462 QTest::newRow("with <script>") << "<html><body><script></script><p>hello world</p></body></html>" << 1;
2463 QTest::newRow("without <script>") << "<html><body><p>hello world</p></body></html>" << 0;
2466 void tst_QWebFrame::javaScriptWindowObjectCleared()
2469 QWebFrame* frame = page.mainFrame();
2470 QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
2471 QFETCH(QString, html);
2472 frame->setHtml(html);
2474 QFETCH(int, signalCount);
2475 QCOMPARE(spy.count(), signalCount);
2478 void tst_QWebFrame::javaScriptWindowObjectClearedOnEvaluate()
2481 QWebFrame* frame = page.mainFrame();
2482 QSignalSpy spy(frame, SIGNAL(javaScriptWindowObjectCleared()));
2483 frame->setHtml("<html></html>");
2484 QCOMPARE(spy.count(), 0);
2485 frame->evaluateJavaScript("var a = 'a';");
2486 QCOMPARE(spy.count(), 1);
2487 // no new clear for a new script:
2488 frame->evaluateJavaScript("var a = 1;");
2489 QCOMPARE(spy.count(), 1);
2492 void tst_QWebFrame::setHtml()
2494 QString html("<html><head></head><body><p>hello world</p></body></html>");
2495 m_view->page()->mainFrame()->setHtml(html);
2496 QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
2499 void tst_QWebFrame::setHtmlWithResource()
2501 QString html("<html><body><p>hello world</p><img src='qrc:/image.png'/></body></html>");
2504 QWebFrame* frame = page.mainFrame();
2506 // in few seconds, the image should be completey loaded
2507 QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
2508 frame->setHtml(html);
2509 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2510 QCOMPARE(spy.count(), 1);
2512 QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
2513 QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
2514 QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
2519 "<link rel='stylesheet' href='qrc:/style.css' type='text/css' />"
2522 "<p id='idP'>some text</p>"
2526 // in few seconds, the CSS should be completey loaded
2527 frame->setHtml(html2);
2528 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2529 QCOMPARE(spy.size(), 2);
2531 QWebElement p = frame->documentElement().findAll("p").at(0);
2532 QCOMPARE(p.styleProperty("color", QWebElement::CascadedStyle), QLatin1String("red"));
2535 void tst_QWebFrame::setHtmlWithBaseURL()
2537 if (!QDir(TESTS_SOURCE_DIR).exists())
2538 QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
2540 QDir::setCurrent(TESTS_SOURCE_DIR);
2542 QString html("<html><body><p>hello world</p><img src='resources/image2.png'/></body></html>");
2545 QWebFrame* frame = page.mainFrame();
2547 // in few seconds, the image should be completey loaded
2548 QSignalSpy spy(&page, SIGNAL(loadFinished(bool)));
2550 frame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
2551 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2552 QCOMPARE(spy.count(), 1);
2554 QCOMPARE(frame->evaluateJavaScript("document.images.length").toInt(), 1);
2555 QCOMPARE(frame->evaluateJavaScript("document.images[0].width").toInt(), 128);
2556 QCOMPARE(frame->evaluateJavaScript("document.images[0].height").toInt(), 128);
2558 // no history item has to be added.
2559 QCOMPARE(m_view->page()->history()->count(), 0);
2562 class MyPage : public QWebPage
2565 MyPage() : QWebPage(), alerts(0) {}
2569 virtual void javaScriptAlert(QWebFrame*, const QString& msg)
2572 QCOMPARE(msg, QString("foo"));
2573 // Should not be enough to trigger deferred loading, since we've upped the HTML
2574 // tokenizer delay in the Qt frameloader. See HTMLTokenizer::continueProcessing()
2579 void tst_QWebFrame::setHtmlWithJSAlert()
2581 QString html("<html><head></head><body><script>alert('foo');</script><p>hello world</p></body></html>");
2583 m_view->setPage(&page);
2584 page.mainFrame()->setHtml(html);
2585 QCOMPARE(page.alerts, 1);
2586 QCOMPARE(m_view->page()->mainFrame()->toHtml(), html);
2589 class TestNetworkManager : public QNetworkAccessManager
2592 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
2594 QList<QUrl> requestedUrls;
2597 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
2598 requestedUrls.append(request.url());
2599 QNetworkRequest redirectedRequest = request;
2600 redirectedRequest.setUrl(QUrl("data:text/html,<p>hello"));
2601 return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData);
2605 void tst_QWebFrame::ipv6HostEncoding()
2607 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
2608 m_page->setNetworkAccessManager(networkManager);
2609 networkManager->requestedUrls.clear();
2611 QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html");
2612 m_view->setHtml("<p>Hi", baseUrl);
2613 m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();"
2614 "r.open('GET', 'http://[::1]/test.xml', false);"
2617 QCOMPARE(networkManager->requestedUrls.count(), 1);
2618 QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml"));
2621 void tst_QWebFrame::metaData()
2623 m_view->setHtml("<html>"
2625 " <meta name=\"description\" content=\"Test description\">"
2626 " <meta name=\"keywords\" content=\"HTML, JavaScript, Css\">"
2630 QMultiMap<QString, QString> metaData = m_view->page()->mainFrame()->metaData();
2632 QCOMPARE(metaData.count(), 2);
2634 QCOMPARE(metaData.value("description"), QString("Test description"));
2635 QCOMPARE(metaData.value("keywords"), QString("HTML, JavaScript, Css"));
2636 QCOMPARE(metaData.value("nonexistant"), QString());
2638 m_view->setHtml("<html>"
2640 " <meta name=\"samekey\" content=\"FirstValue\">"
2641 " <meta name=\"samekey\" content=\"SecondValue\">"
2645 metaData = m_view->page()->mainFrame()->metaData();
2647 QCOMPARE(metaData.count(), 2);
2649 QStringList values = metaData.values("samekey");
2650 QCOMPARE(values.count(), 2);
2652 QVERIFY(values.contains("FirstValue"));
2653 QVERIFY(values.contains("SecondValue"));
2655 QCOMPARE(metaData.value("nonexistant"), QString());
2658 #if !defined(Q_WS_MAEMO_5)
2659 void tst_QWebFrame::popupFocus()
2662 view.setHtml("<html>"
2664 " <select name=\"select\">"
2665 " <option>1</option>"
2666 " <option>2</option>"
2668 " <input type=\"text\"> </input>"
2669 " <textarea name=\"text_area\" rows=\"3\" cols=\"40\">"
2670 "This test checks whether showing and hiding a popup"
2671 "takes the focus away from the webpage."
2675 view.resize(400, 100);
2678 QTRY_VERIFY(view.hasFocus());
2680 // open the popup by clicking. check if focus is on the popup
2681 const QWebElement webCombo = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("select[name=select]"));
2682 QTest::mouseClick(&view, Qt::LeftButton, 0, webCombo.geometry().center());
2683 QObject* webpopup = firstChildByClassName(&view, "QComboBox");
2684 QComboBox* combo = qobject_cast<QComboBox*>(webpopup);
2685 QVERIFY(combo != 0);
2686 QTRY_VERIFY(!view.hasFocus() && combo->view()->hasFocus()); // Focus should be on the popup
2688 // hide the popup and check if focus is on the page
2690 QTRY_VERIFY(view.hasFocus() && !combo->view()->hasFocus()); // Focus should be back on the WebView
2694 void tst_QWebFrame::inputFieldFocus()
2697 view.setHtml("<html><body><input type=\"text\"></input></body></html>");
2698 view.resize(400, 100);
2700 QTest::qWaitForWindowShown(&view);
2702 QTRY_VERIFY(view.hasFocus());
2704 // double the flashing time, should at least blink once already
2705 int delay = qApp->cursorFlashTime() * 2;
2707 // focus the lineedit and check if it blinks
2708 const QWebElement inputElement = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("input[type=text]"));
2709 QTest::mouseClick(&view, Qt::LeftButton, 0, inputElement.geometry().center());
2710 m_inputFieldsTestView = &view;
2711 view.installEventFilter( this );
2712 QTest::qWait(delay);
2713 QVERIFY2(m_inputFieldTestPaintCount >= 3,
2714 "The input field should have a blinking caret");
2717 void tst_QWebFrame::hitTestContent()
2719 QString html("<html><body><p>A paragraph</p><br/><br/><br/><a href=\"about:blank\" target=\"_foo\" id=\"link\">link text</a></body></html>");
2722 QWebFrame* frame = page.mainFrame();
2723 frame->setHtml(html);
2724 page.setViewportSize(QSize(200, 0)); //no height so link is not visible
2725 const QWebElement linkElement = frame->documentElement().findFirst(QLatin1String("a#link"));
2726 QWebHitTestResult result = frame->hitTestContent(linkElement.geometry().center());
2727 QCOMPARE(result.linkText(), QString("link text"));
2728 QWebElement link = result.linkElement();
2729 QCOMPARE(link.attribute("target"), QString("_foo"));
2732 void tst_QWebFrame::jsByteArray()
2734 QByteArray ba("hello world");
2735 m_myObject->setByteArrayProperty(ba);
2737 // read-only property
2738 QCOMPARE(m_myObject->byteArrayProperty(), ba);
2740 QVariant v = evalJSV("myObject.byteArrayProperty");
2741 QCOMPARE(int(v.type()), int(QVariant::ByteArray));
2743 QCOMPARE(v.toByteArray(), ba);
2746 void tst_QWebFrame::ownership()
2750 QPointer<QObject> ptr = new QObject();
2754 QWebFrame* frame = page.mainFrame();
2755 frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::ScriptOwnership);
2760 QPointer<QObject> ptr = new QObject();
2762 QObject* before = ptr;
2765 QWebFrame* frame = page.mainFrame();
2766 frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::QtOwnership);
2768 QVERIFY(ptr == before);
2772 QObject* parent = new QObject();
2773 QObject* child = new QObject(parent);
2775 QWebFrame* frame = page.mainFrame();
2776 frame->addToJavaScriptWindowObject("test", child, QScriptEngine::QtOwnership);
2777 QVariant v = frame->evaluateJavaScript("test");
2778 QCOMPARE(qvariant_cast<QObject*>(v), child);
2780 v = frame->evaluateJavaScript("test");
2781 QCOMPARE(qvariant_cast<QObject*>(v), (QObject *)0);
2784 QPointer<QObject> ptr = new QObject();
2788 QWebFrame* frame = page.mainFrame();
2789 frame->addToJavaScriptWindowObject("test", ptr, QScriptEngine::AutoOwnership);
2791 // no parent, so it should be like ScriptOwnership
2795 QObject* parent = new QObject();
2796 QPointer<QObject> child = new QObject(parent);
2797 QVERIFY(child != 0);
2800 QWebFrame* frame = page.mainFrame();
2801 frame->addToJavaScriptWindowObject("test", child, QScriptEngine::AutoOwnership);
2803 // has parent, so it should be like QtOwnership
2804 QVERIFY(child != 0);
2809 void tst_QWebFrame::nullValue()
2811 QVariant v = m_view->page()->mainFrame()->evaluateJavaScript("null");
2812 QVERIFY(v.isNull());
2815 void tst_QWebFrame::baseUrl_data()
2817 QTest::addColumn<QString>("html");
2818 QTest::addColumn<QUrl>("loadUrl");
2819 QTest::addColumn<QUrl>("url");
2820 QTest::addColumn<QUrl>("baseUrl");
2822 QTest::newRow("null") << QString() << QUrl()
2823 << QUrl("about:blank") << QUrl("about:blank");
2825 QTest::newRow("foo") << QString() << QUrl("http://foobar.baz/")
2826 << QUrl("http://foobar.baz/") << QUrl("http://foobar.baz/");
2828 QString html = "<html>"
2830 "<base href=\"http://foobaz.bar/\" />"
2833 QTest::newRow("customBaseUrl") << html << QUrl("http://foobar.baz/")
2834 << QUrl("http://foobar.baz/") << QUrl("http://foobaz.bar/");
2837 void tst_QWebFrame::baseUrl()
2839 QFETCH(QString, html);
2840 QFETCH(QUrl, loadUrl);
2842 QFETCH(QUrl, baseUrl);
2844 m_page->mainFrame()->setHtml(html, loadUrl);
2845 QCOMPARE(m_page->mainFrame()->url(), url);
2846 QCOMPARE(m_page->mainFrame()->baseUrl(), baseUrl);
2849 void tst_QWebFrame::hasSetFocus()
2851 QString html("<html><body><p>top</p>" \
2852 "<iframe width='80%' height='30%'/>" \
2855 QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool)));
2856 m_page->mainFrame()->setHtml(html);
2858 waitForSignal(m_page->mainFrame(), SIGNAL(loadFinished(bool)), 200);
2859 QCOMPARE(loadSpy.size(), 1);
2861 QList<QWebFrame*> children = m_page->mainFrame()->childFrames();
2862 QWebFrame* frame = children.at(0);
2863 QString innerHtml("<html><body><p>another iframe</p>" \
2864 "<iframe width='80%' height='30%'/>" \
2866 frame->setHtml(innerHtml);
2868 waitForSignal(frame, SIGNAL(loadFinished(bool)), 200);
2869 QCOMPARE(loadSpy.size(), 2);
2871 m_page->mainFrame()->setFocus();
2872 QTRY_VERIFY(m_page->mainFrame()->hasFocus());
2874 for (int i = 0; i < children.size(); ++i) {
2875 children.at(i)->setFocus();
2876 QTRY_VERIFY(children.at(i)->hasFocus());
2877 QVERIFY(!m_page->mainFrame()->hasFocus());
2880 m_page->mainFrame()->setFocus();
2881 QTRY_VERIFY(m_page->mainFrame()->hasFocus());
2884 void tst_QWebFrame::render()
2886 QString html("<html>" \
2888 "body, iframe { margin: 0px; border: none; }" \
2890 "<body><iframe width='100px' height='100px'/></body>" \
2894 page.mainFrame()->setHtml(html);
2896 QList<QWebFrame*> frames = page.mainFrame()->childFrames();
2897 QWebFrame *frame = frames.at(0);
2898 QString innerHtml("<body style='margin: 0px;'><img src='qrc:/image.png'/></body>");
2899 frame->setHtml(innerHtml);
2903 QSize size = page.mainFrame()->contentsSize();
2904 page.setViewportSize(size);
2906 // render contents layer only (the iframe is smaller than the image, so it will have scrollbars)
2907 QPainter painter1(&picture);
2908 frame->render(&painter1, QWebFrame::ContentsLayer);
2911 QCOMPARE(size.width(), picture.boundingRect().width() + frame->scrollBarGeometry(Qt::Vertical).width());
2912 QCOMPARE(size.height(), picture.boundingRect().height() + frame->scrollBarGeometry(Qt::Horizontal).height());
2914 // render everything, should be the size of the iframe
2915 QPainter painter2(&picture);
2916 frame->render(&painter2, QWebFrame::AllLayers);
2919 QCOMPARE(size.width(), picture.boundingRect().width()); // width: 100px
2920 QCOMPARE(size.height(), picture.boundingRect().height()); // height: 100px
2923 void tst_QWebFrame::scrollPosition()
2925 // enlarged image in a small viewport, to provoke the scrollbars to appear
2926 QString html("<html><body><img src='qrc:/image.png' height=500 width=500/></body></html>");
2929 page.setViewportSize(QSize(200, 200));
2931 QWebFrame* frame = page.mainFrame();
2932 frame->setHtml(html);
2933 frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
2934 frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
2936 // try to set the scroll offset programmatically
2937 frame->setScrollPosition(QPoint(23, 29));
2938 QCOMPARE(frame->scrollPosition().x(), 23);
2939 QCOMPARE(frame->scrollPosition().y(), 29);
2941 int x = frame->evaluateJavaScript("window.scrollX").toInt();
2942 int y = frame->evaluateJavaScript("window.scrollY").toInt();
2947 void tst_QWebFrame::scrollToAnchor()
2950 page.setViewportSize(QSize(480, 800));
2951 QWebFrame* frame = page.mainFrame();
2953 QString html("<html><body><p style=\"margin-bottom: 1500px;\">Hello.</p>"
2954 "<p><a id=\"foo\">This</a> is an anchor</p>"
2955 "<p style=\"margin-bottom: 1500px;\"><a id=\"bar\">This</a> is another anchor</p>"
2957 frame->setHtml(html);
2958 frame->setScrollPosition(QPoint(0, 0));
2959 QCOMPARE(frame->scrollPosition().x(), 0);
2960 QCOMPARE(frame->scrollPosition().y(), 0);
2962 QWebElement fooAnchor = frame->findFirstElement("a[id=foo]");
2964 frame->scrollToAnchor("foo");
2965 QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
2967 frame->scrollToAnchor("bar");
2968 frame->scrollToAnchor("foo");
2969 QCOMPARE(frame->scrollPosition().y(), fooAnchor.geometry().top());
2971 frame->scrollToAnchor("top");
2972 QCOMPARE(frame->scrollPosition().y(), 0);
2974 frame->scrollToAnchor("bar");
2975 frame->scrollToAnchor("notexist");
2976 QVERIFY(frame->scrollPosition().y() != 0);
2980 void tst_QWebFrame::scrollbarsOff()
2983 QWebFrame* mainFrame = view.page()->mainFrame();
2985 mainFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
2986 mainFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
2988 QString html("<script>" \
2989 " function checkScrollbar() {" \
2990 " if (innerWidth === document.documentElement.offsetWidth)" \
2991 " document.getElementById('span1').innerText = 'SUCCESS';" \
2993 " document.getElementById('span1').innerText = 'FAIL';" \
2997 " <div style='margin-top:1000px ; margin-left:1000px'>" \
2998 " <a id='offscreen' href='a'>End</a>" \
3000 "<span id='span1'></span>" \
3005 ::waitForSignal(&view, SIGNAL(loadFinished(bool)));
3007 mainFrame->evaluateJavaScript("checkScrollbar();");
3008 QCOMPARE(mainFrame->documentElement().findAll("span").at(0).toPlainText(), QString("SUCCESS"));
3011 void tst_QWebFrame::evaluateWillCauseRepaint()
3014 QString html("<html><body>top<div id=\"junk\" style=\"display: block;\">"
3015 "junk</div>bottom</body></html>");
3019 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
3020 QTest::qWaitForWindowShown(&view);
3025 view.page()->mainFrame()->evaluateJavaScript(
3026 "document.getElementById('junk').style.display = 'none';");
3028 ::waitForSignal(view.page(), SIGNAL(repaintRequested(QRect)));
3031 class TestFactory : public QObject
3036 : obj(0), counter(0)
3039 Q_INVOKABLE QObject* getNewObject()
3042 obj = new QObject(this);
3043 obj->setObjectName(QLatin1String("test") + QString::number(++counter));
3052 void tst_QWebFrame::qObjectWrapperWithSameIdentity()
3054 m_view->setHtml("<script>function triggerBug() { document.getElementById('span1').innerText = test.getNewObject().objectName; }</script>"
3055 "<body><span id='span1'>test</span></body>");
3057 QWebFrame* mainFrame = m_view->page()->mainFrame();
3058 QCOMPARE(mainFrame->toPlainText(), QString("test"));
3060 mainFrame->addToJavaScriptWindowObject("test", new TestFactory, QScriptEngine::ScriptOwnership);
3062 mainFrame->evaluateJavaScript("triggerBug();");
3063 QCOMPARE(mainFrame->toPlainText(), QString("test1"));
3065 mainFrame->evaluateJavaScript("triggerBug();");
3066 QCOMPARE(mainFrame->toPlainText(), QString("test2"));
3069 void tst_QWebFrame::introspectQtMethods_data()
3071 QTest::addColumn<QString>("objectExpression");
3072 QTest::addColumn<QString>("methodName");
3073 QTest::addColumn<QStringList>("expectedPropertyNames");
3075 QTest::newRow("myObject.mySignal")
3076 << "myObject" << "mySignal" << (QStringList() << "connect" << "disconnect" << "length" << "name");
3077 QTest::newRow("myObject.mySlot")
3078 << "myObject" << "mySlot" << (QStringList() << "connect" << "disconnect" << "length" << "name");
3079 QTest::newRow("myObject.myInvokable")
3080 << "myObject" << "myInvokable" << (QStringList() << "connect" << "disconnect" << "length" << "name");
3081 QTest::newRow("myObject.mySignal.connect")
3082 << "myObject.mySignal" << "connect" << (QStringList() << "length" << "name");
3083 QTest::newRow("myObject.mySignal.disconnect")
3084 << "myObject.mySignal" << "disconnect" << (QStringList() << "length" << "name");
3087 void tst_QWebFrame::introspectQtMethods()
3089 QFETCH(QString, objectExpression);
3090 QFETCH(QString, methodName);
3091 QFETCH(QStringList, expectedPropertyNames);
3093 QString methodLookup = QString::fromLatin1("%0['%1']").arg(objectExpression).arg(methodName);
3094 QCOMPARE(evalJSV(QString::fromLatin1("Object.getOwnPropertyNames(%0).sort()").arg(methodLookup)).toStringList(), expectedPropertyNames);
3096 for (int i = 0; i < expectedPropertyNames.size(); ++i) {
3097 QString name = expectedPropertyNames.at(i);
3098 QCOMPARE(evalJS(QString::fromLatin1("%0.hasOwnProperty('%1')").arg(methodLookup).arg(name)), sTrue);
3099 evalJS(QString::fromLatin1("var descriptor = Object.getOwnPropertyDescriptor(%0, '%1')").arg(methodLookup).arg(name));
3100 QCOMPARE(evalJS("typeof descriptor"), QString::fromLatin1("object"));
3101 QCOMPARE(evalJS("descriptor.get"), sUndefined);
3102 QCOMPARE(evalJS("descriptor.set"), sUndefined);
3103 QCOMPARE(evalJS(QString::fromLatin1("descriptor.value === %0['%1']").arg(methodLookup).arg(name)), sTrue);
3104 QCOMPARE(evalJS(QString::fromLatin1("descriptor.enumerable")), sFalse);
3105 QCOMPARE(evalJS(QString::fromLatin1("descriptor.configurable")), sFalse);
3108 QVERIFY(evalJSV("var props=[]; for (var p in myObject.deleteLater) {props.push(p);}; props.sort()").toStringList().isEmpty());
3111 void tst_QWebFrame::setContent_data()
3113 QTest::addColumn<QString>("mimeType");
3114 QTest::addColumn<QByteArray>("testContents");
3115 QTest::addColumn<QString>("expected");
3117 QString str = QString::fromUtf8("ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει");
3118 QTest::newRow("UTF-8 plain text") << "text/plain; charset=utf-8" << str.toUtf8() << str;
3120 QTextCodec *utf16 = QTextCodec::codecForName("UTF-16");
3122 QTest::newRow("UTF-16 plain text") << "text/plain; charset=utf-16" << utf16->fromUnicode(str) << str;
3124 str = QString::fromUtf8("Une chaîne de caractères à sa façon.");
3125 QTest::newRow("latin-1 plain text") << "text/plain; charset=iso-8859-1" << str.toLatin1() << str;
3130 void tst_QWebFrame::setContent()
3132 QFETCH(QString, mimeType);
3133 QFETCH(QByteArray, testContents);
3134 QFETCH(QString, expected);
3135 m_view->setContent(testContents, mimeType);
3136 QWebFrame* mainFrame = m_view->page()->mainFrame();
3137 QCOMPARE(expected , mainFrame->toPlainText());
3140 QTEST_MAIN(tst_QWebFrame)
3141 #include "tst_qwebframe.moc"