Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Provide a mechanism for reporting JS syntax errors.

  • Loading branch information...
commit 55bb8f2199c33fe5a2fb6216280e74de2b025e41 1 parent 86b0c80
@xian xian authored
View
82 lib/jasmine-core/jasmine.js
@@ -951,6 +951,86 @@ jasmine.Env.prototype.contains_ = function(haystack, needle) {
jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
this.equalityTesters_.push(equalityTester);
};
+
+/**
+ * Notify Jasmine that a JS file is about to be loaded.
+ *
+ * If a function is provided as the optional second parameter, that function will be called
+ * to register an error handler, and the function should return the previous error handler, if any.
+ *
+ * The error handler is a function taking three arguments (message, file, and line) that should
+ * be invoked when there is a JavaScript error.
+ *
+ * @param file
+ * @param optional_registerOnErrorFn Optional function which registers an error callback function and returns the prior value.
+ */
+jasmine.Env.prototype.aboutToLoad = function(file, optional_registerOnErrorFn) {
+ var self = this;
+ this.currentlyLoadingFile_ = {
+ name: file,
+ finished: false,
+ errors: [],
+ registerOnErrorFn: optional_registerOnErrorFn
+ };
+
+ if (optional_registerOnErrorFn) {
+ this.currentlyLoadingFile_.oldOnError = optional_registerOnErrorFn(function(message, file, line) { self.loadError(message, file, line); });
+ }
+};
+
+/**
+ * Notify Jasmine that there was an error while loading a JS file.
+ *
+ * @param message The error message.
+ * @param file The file causing the error.
+ * @param line The line number causing the error.
+ */
+jasmine.Env.prototype.loadError = function(message, file, line) {
+ if (!this.currentlyLoadingFile_) { throw new Error("Received an error, but no file is loading!"); }
+ this.currentlyLoadingFile_.errors.push({
+ message:message,
+ file:file,
+ line:line
+ });
+};
+
+/**
+ * Notify Jasmine that the currently-loading JS file has finished.
+ */
+jasmine.Env.prototype.finishedLoading = function() {
+ if (!this.currentlyLoadingFile_) { throw new Error("No file should be loading!"); }
+ this.currentlyLoadingFile_.finished = true;
+ if (this.currentlyLoadingFile_.registerOnErrorFn) {
+ this.currentlyLoadingFile_.registerOnErrorFn(this.currentlyLoadingFile_.oldOnError);
+ }
+};
+
+/**
+ * Request that Jasmine generate a failing spec if the current JS file had any syntax errors or failed to load.
+ */
+jasmine.Env.prototype.generateFileLoadErrors = function() {
+ if (!this.currentlyLoadingFile_) { throw new Error("No file should be loading!"); }
+ var currentFile = this.currentlyLoadingFile_;
+
+ var env = this;
+ if (!currentFile.finished || currentFile.errors.length) {
+ env.describe("File " + currentFile.name, function() {
+ env.it("should have successfully loaded", function() {
+ if (!currentFile.finished) {
+ this.fail(currentFile.name + " failed to load");
+ }
+
+ if (currentFile.errors.length) {
+ for (var j = 0; j < currentFile.errors.length; j++) {
+ var error = currentFile.errors[j];
+ this.fail(currentFile.name + ": " + error.message + " at " + error.file + ":" + error.line);
+ }
+ }
+ });
+ });
+ }
+};
+
/** No-op base class for Jasmine reporters.
*
* @constructor
@@ -2472,5 +2552,5 @@ jasmine.version_= {
"major": 1,
"minor": 1,
"build": 0,
- "revision": 1320442951
+ "revision": 1326762108
};
View
99 spec/core/EnvSpec.js
@@ -156,4 +156,103 @@ describe("jasmine.Env", function() {
});
});
});
+
+ describe("file load errors", function() {
+ function suiteNames(suites) {
+ var suiteDescriptions = [];
+ for (var i = 0; i < suites.length; i++) {
+ suiteDescriptions.push(suites[i].getFullName());
+ }
+ return suiteDescriptions;
+ }
+
+ function messagesFrom(env) {
+ var messages = [];
+ var suites = env.currentRunner().topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var subsuites = suite.suites();
+ for (var j = 0; j < subsuites.length; j++) {
+ suites.push(subsuites[j]);
+ }
+ var specs = suite.specs();
+ for (j = 0; j < specs.length; j++) {
+ var spec = specs[j];
+ var items = spec.results().getItems();
+ for (var k = 0; k < items.length; k++) {
+ messages.push("[" + spec.getFullName() + "] " + items[k].toString());
+ }
+ }
+ }
+ return messages;
+ }
+
+ it("should create no extra suites or specs if the file loads properly", function () {
+ env.aboutToLoad("some/file.js");
+ env.finishedLoading();
+ env.generateFileLoadErrors();
+
+ env.currentRunner().execute();
+ var runnerResults = env.currentRunner().results();
+ expect(runnerResults.totalCount).toEqual(0);
+ expect(runnerResults.passedCount).toEqual(0);
+ });
+
+ it("should create a failing spec if a file fails to signal that it loaded", function () {
+ env.aboutToLoad("some/file.js");
+ env.describe("Specs in some/file");
+ env.generateFileLoadErrors();
+
+ env.aboutToLoad("some/other/file.js");
+ env.describe("Specs in some/other/file");
+ env.generateFileLoadErrors();
+
+ env.currentRunner().execute();
+ var runnerResults = env.currentRunner().results();
+ expect(runnerResults.totalCount).toEqual(4);
+ expect(runnerResults.passedCount).toEqual(0);
+ var suites = env.currentRunner().topLevelSuites();
+ expect(suiteNames(suites)).toEqual([
+ "Specs in some/file",
+ "File some/file.js",
+ "Specs in some/other/file",
+ "File some/other/file.js"
+ ]);
+ });
+
+ it("should create a failing spec if loading a file generates errors", function () {
+ env.aboutToLoad("some/file.js");
+ env.loadError("syntax error", "some/file.js", 15);
+ env.generateFileLoadErrors();
+
+ env.currentRunner().execute();
+ var runnerResults = env.currentRunner().results();
+ expect(runnerResults.totalCount).toEqual(2);
+ expect(runnerResults.passedCount).toEqual(0);
+ var suites = env.currentRunner().topLevelSuites();
+ expect(suiteNames(suites)).toEqual([ "File some/file.js" ]);
+ expect(messagesFrom(env)).toContain("[File some/file.js should have successfully loaded.] some/file.js: syntax error at some/file.js:15");
+ });
+
+ it("should set and restore an error handler via the provided function", function () {
+ var fakeOnError = "original value";
+ env.aboutToLoad("some/file.js", function(onError) {
+ var old = fakeOnError;
+ fakeOnError = onError;
+ return old;
+ });
+ expect(fakeOnError).not.toEqual("original value");
+ fakeOnError.call(null, "error message", "filename", 123);
+ env.finishedLoading();
+ expect(fakeOnError).toEqual("original value");
+
+ env.generateFileLoadErrors();
+
+ env.currentRunner().execute();
+ var runnerResults = env.currentRunner().results();
+ expect(runnerResults.totalCount).toEqual(1);
+ expect(runnerResults.passedCount).toEqual(0);
+ expect(messagesFrom(env)).toContain("[File some/file.js should have successfully loaded.] some/file.js: error message at filename:123");
+ });
+ });
});
View
80 src/core/Env.js
@@ -267,3 +267,83 @@ jasmine.Env.prototype.contains_ = function(haystack, needle) {
jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
this.equalityTesters_.push(equalityTester);
};
+
+/**
+ * Notify Jasmine that a JS file is about to be loaded.
+ *
+ * If a function is provided as the optional second parameter, that function will be called
+ * to register an error handler, and the function should return the previous error handler, if any.
+ *
+ * The error handler is a function taking three arguments (message, file, and line) that should
+ * be invoked when there is a JavaScript error.
+ *
+ * @param file
+ * @param optional_registerOnErrorFn Optional function which registers an error callback function and returns the prior value.
+ */
+jasmine.Env.prototype.aboutToLoad = function(file, optional_registerOnErrorFn) {
+ var self = this;
+ this.currentlyLoadingFile_ = {
+ name: file,
+ finished: false,
+ errors: [],
+ registerOnErrorFn: optional_registerOnErrorFn
+ };
+
+ if (optional_registerOnErrorFn) {
+ this.currentlyLoadingFile_.oldOnError = optional_registerOnErrorFn(function(message, file, line) { self.loadError(message, file, line); });
+ }
+};
+
+/**
+ * Notify Jasmine that there was an error while loading a JS file.
+ *
+ * @param message The error message.
+ * @param file The file causing the error.
+ * @param line The line number causing the error.
+ */
+jasmine.Env.prototype.loadError = function(message, file, line) {
+ if (!this.currentlyLoadingFile_) { throw new Error("Received an error, but no file is loading!"); }
+ this.currentlyLoadingFile_.errors.push({
+ message:message,
+ file:file,
+ line:line
+ });
+};
+
+/**
+ * Notify Jasmine that the currently-loading JS file has finished.
+ */
+jasmine.Env.prototype.finishedLoading = function() {
+ if (!this.currentlyLoadingFile_) { throw new Error("No file should be loading!"); }
+ this.currentlyLoadingFile_.finished = true;
+ if (this.currentlyLoadingFile_.registerOnErrorFn) {
+ this.currentlyLoadingFile_.registerOnErrorFn(this.currentlyLoadingFile_.oldOnError);
+ }
+};
+
+/**
+ * Request that Jasmine generate a failing spec if the current JS file had any syntax errors or failed to load.
+ */
+jasmine.Env.prototype.generateFileLoadErrors = function() {
+ if (!this.currentlyLoadingFile_) { throw new Error("No file should be loading!"); }
+ var currentFile = this.currentlyLoadingFile_;
+
+ var env = this;
+ if (!currentFile.finished || currentFile.errors.length) {
+ env.describe("File " + currentFile.name, function() {
+ env.it("should have successfully loaded", function() {
+ if (!currentFile.finished) {
+ this.fail(currentFile.name + " failed to load");
+ }
+
+ if (currentFile.errors.length) {
+ for (var j = 0; j < currentFile.errors.length; j++) {
+ var error = currentFile.errors[j];
+ this.fail(currentFile.name + ": " + error.message + " at " + error.file + ":" + error.line);
+ }
+ }
+ });
+ });
+ }
+};
+
View
2  src/version.js
@@ -2,5 +2,5 @@ jasmine.version_= {
"major": 1,
"minor": 1,
"build": 0,
- "revision": 1320442951
+ "revision": 1326762108
};
Please sign in to comment.
Something went wrong with that request. Please try again.