From 13bcd5226e6a5463335e5afbf6dbc413baec8b55 Mon Sep 17 00:00:00 2001 From: John Bintz <john@coswellproductions.com> Date: Fri, 22 Jul 2011 07:42:25 -0400 Subject: [PATCH] ensure a spec can't leave the page, causing a craaaazy loop --- ext/jasmine-webkit-specrunner/specrunner.cpp | 37 ++++++++++++++++++-- jasmine/jasmine.headless-reporter.coffee | 3 +- jasmine/jasmine.headless-reporter.js | 6 +++- lib/jasmine/template_writer.rb | 14 +++++++- spec/bin/jasmine-headless-webkit_spec.rb | 9 +++++ spec/jasmine/leave_page/leave_page.js | 4 +++ spec/jasmine/leave_page/leave_page.yml | 9 +++++ spec/jasmine/leave_page/leave_page_spec.js | 11 ++++++ 8 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 spec/jasmine/leave_page/leave_page.js create mode 100644 spec/jasmine/leave_page/leave_page.yml create mode 100644 spec/jasmine/leave_page/leave_page_spec.js diff --git a/ext/jasmine-webkit-specrunner/specrunner.cpp b/ext/jasmine-webkit-specrunner/specrunner.cpp index 1a52982..d6b0c3c 100644 --- a/ext/jasmine-webkit-specrunner/specrunner.cpp +++ b/ext/jasmine-webkit-specrunner/specrunner.cpp @@ -35,6 +35,9 @@ class HeadlessSpecRunnerPage: public QWebPage { Q_OBJECT +public: + HeadlessSpecRunnerPage(); + void oneFalseConfirm(); signals: void consoleLog(const QString &msg, int lineNumber, const QString &sourceID); void internalLog(const QString ¬e, const QString &msg); @@ -42,8 +45,17 @@ protected: void javaScriptConsoleMessage(const QString & message, int lineNumber, const QString & sourceID); bool javaScriptConfirm(QWebFrame *frame, const QString &msg); void javaScriptAlert(QWebFrame *frame, const QString &msg); +private: + bool confirmResult; }; +HeadlessSpecRunnerPage::HeadlessSpecRunnerPage() + : QWebPage() + , confirmResult(true) +{ + +} + void HeadlessSpecRunnerPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID) { emit consoleLog(message, lineNumber, sourceID); @@ -51,8 +63,13 @@ void HeadlessSpecRunnerPage::javaScriptConsoleMessage(const QString &message, in bool HeadlessSpecRunnerPage::javaScriptConfirm(QWebFrame *frame, const QString &msg) { - emit internalLog("TODO", "jasmine-headless-webkit can't handle confirm() yet! You should mock window.confirm for now. Returning true."); - return true; + if (confirmResult) { + emit internalLog("TODO", "jasmine-headless-webkit can't handle confirm() yet! You should mock window.confirm for now. Returning true."); + return true; + } else { + confirmResult = true; + return false; + } } void HeadlessSpecRunnerPage::javaScriptAlert(QWebFrame *frame, const QString &msg) @@ -60,6 +77,11 @@ void HeadlessSpecRunnerPage::javaScriptAlert(QWebFrame *frame, const QString &ms emit internalLog("alert", msg); } +void HeadlessSpecRunnerPage::oneFalseConfirm() +{ + confirmResult = false; +} + class HeadlessSpecRunner: public QObject { Q_OBJECT @@ -71,6 +93,7 @@ public: void go(); public slots: void log(const QString &msg); + void leavePageAttempt(const QString &msg); void specPassed(); void specFailed(const QString &specDetail); void printName(const QString &name); @@ -250,6 +273,16 @@ void HeadlessSpecRunner::log(const QString &msg) std::cout << std::endl; } +void HeadlessSpecRunner::leavePageAttempt(const QString &msg) +{ + red(); + std::cout << "[error] "; + clear(); + std::cout << qPrintable(msg) << std::endl; + m_page.oneFalseConfirm(); + hasErrors = true; +} + void HeadlessSpecRunner::printName(const QString &name) { std::cout << std::endl << std::endl; diff --git a/jasmine/jasmine.headless-reporter.coffee b/jasmine/jasmine.headless-reporter.coffee index 447c102..b759f64 100644 --- a/jasmine/jasmine.headless-reporter.coffee +++ b/jasmine/jasmine.headless-reporter.coffee @@ -50,7 +50,7 @@ jasmine.Spec.prototype.getSpecSplitName = -> parts class jasmine.HeadlessReporter - constructor: -> + constructor: (@callback = null) -> @results = [] @failedCount = 0 @length = 0 @@ -59,6 +59,7 @@ class jasmine.HeadlessReporter do (result) => result.print() + this.callback() if @callback JHW.finishSuite((new Date() - @startTime) / 1000.0, @length, @failedCount) reportRunnerStarting: (runner) -> @startTime = new Date() diff --git a/jasmine/jasmine.headless-reporter.js b/jasmine/jasmine.headless-reporter.js index d9b4eb5..53f2be2 100644 --- a/jasmine/jasmine.headless-reporter.js +++ b/jasmine/jasmine.headless-reporter.js @@ -83,7 +83,8 @@ return parts; }; jasmine.HeadlessReporter = (function() { - function HeadlessReporter() { + function HeadlessReporter(callback) { + this.callback = callback != null ? callback : null; this.results = []; this.failedCount = 0; this.length = 0; @@ -98,6 +99,9 @@ result = _ref[_i]; _fn(result); } + if (this.callback) { + this.callback(); + } return JHW.finishSuite((new Date() - this.startTime) / 1000.0, this.length, this.failedCount); }; HeadlessReporter.prototype.reportRunnerStarting = function(runner) { diff --git a/lib/jasmine/template_writer.rb b/lib/jasmine/template_writer.rb index 6a99ca4..762dd7e 100644 --- a/lib/jasmine/template_writer.rb +++ b/lib/jasmine/template_writer.rb @@ -31,6 +31,16 @@ module Jasmine }, pp: function(data) { JHW.log(jasmine ? jasmine.pp(data) : JSON.stringify(data)); } }; + + window.onbeforeunload = function(e) { + JHW.leavePageAttempt('The code tried to leave the test page. Check for unhandled form submits and link clicks.'); + + if (e = e || window.event) { + e.returnValue = "leaving"; + } + + return "leaving"; + }; </script> #{files.join("\n")} <script type="text/javascript"> @@ -40,7 +50,9 @@ HeadlessReporterResult.specLineNumbers = #{MultiJson.encode(spec_lines)}; <body> <script type="text/javascript"> - jasmine.getEnv().addReporter(new jasmine.HeadlessReporter()); + jasmine.getEnv().addReporter(new jasmine.HeadlessReporter(function() { + window.onbeforeunload = null; + })); jasmine.getEnv().execute(); </script> diff --git a/spec/bin/jasmine-headless-webkit_spec.rb b/spec/bin/jasmine-headless-webkit_spec.rb index cee4707..c40590d 100644 --- a/spec/bin/jasmine-headless-webkit_spec.rb +++ b/spec/bin/jasmine-headless-webkit_spec.rb @@ -60,6 +60,15 @@ describe "jasmine-headless-webkit" do end end + describe 'tries to leave page' do + it "should not leave the page nor loop" do + system %{bin/jasmine-headless-webkit -j spec/jasmine/leave_page/leave_page.yml --report #{report}} + $?.exitstatus.should == 1 + + report.should be_a_report_containing(2, 0, false) + end + end + describe 'with filtered run' do context "don't run a full run, just the filtered run" do it "should succeed and run both" do diff --git a/spec/jasmine/leave_page/leave_page.js b/spec/jasmine/leave_page/leave_page.js new file mode 100644 index 0000000..22f336b --- /dev/null +++ b/spec/jasmine/leave_page/leave_page.js @@ -0,0 +1,4 @@ +function yes() { + document.location.href = 'http://www.google.com/' +} + diff --git a/spec/jasmine/leave_page/leave_page.yml b/spec/jasmine/leave_page/leave_page.yml new file mode 100644 index 0000000..f434433 --- /dev/null +++ b/spec/jasmine/leave_page/leave_page.yml @@ -0,0 +1,9 @@ +src_files: + - spec/jasmine/leave_page/leave_page.js + +spec_files: + - spec/jasmine/leave_page/leave_page_spec.js + +src_dir: . +spec_dir: . + diff --git a/spec/jasmine/leave_page/leave_page_spec.js b/spec/jasmine/leave_page/leave_page_spec.js new file mode 100644 index 0000000..6593c00 --- /dev/null +++ b/spec/jasmine/leave_page/leave_page_spec.js @@ -0,0 +1,11 @@ +describe("something", function() { + it("should be true", function() { + yes(); + expect(true).toEqual(true); + }); + + it("should so something else", function() { + expect(true).toEqual(true); + }); +}); +