summaryrefslogtreecommitdiffstats
path: root/testing/modules/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/modules/tests
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/modules/tests')
-rw-r--r--testing/modules/tests/browser/browser.toml3
-rw-r--r--testing/modules/tests/browser/browser_test_assert.js21
-rw-r--r--testing/modules/tests/xpcshell/test_assert.js491
-rw-r--r--testing/modules/tests/xpcshell/test_mockRegistrar.js65
-rw-r--r--testing/modules/tests/xpcshell/test_structuredlog.js147
-rw-r--r--testing/modules/tests/xpcshell/xpcshell.toml8
6 files changed, 735 insertions, 0 deletions
diff --git a/testing/modules/tests/browser/browser.toml b/testing/modules/tests/browser/browser.toml
new file mode 100644
index 0000000000..17432d1d8c
--- /dev/null
+++ b/testing/modules/tests/browser/browser.toml
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+["browser_test_assert.js"]
diff --git a/testing/modules/tests/browser/browser_test_assert.js b/testing/modules/tests/browser/browser_test_assert.js
new file mode 100644
index 0000000000..ea0823e60d
--- /dev/null
+++ b/testing/modules/tests/browser/browser_test_assert.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+ export_assertions();
+
+ ok(true, "pass ok");
+ is(true, true, "pass is");
+ isnot(false, true, "pass isnot");
+ todo(false, "pass todo");
+ todo_is(false, true, "pass todo_is");
+ todo_isnot(true, true, "pass todo_isnot");
+ info("info message");
+
+ var func = is;
+ func(1, 1, "pass indirect is");
+
+ stringMatches("hello world", /llo\s/);
+ stringMatches("hello world", "llo\\s");
+ stringContains("hello world", "llo");
+}
diff --git a/testing/modules/tests/xpcshell/test_assert.js b/testing/modules/tests/xpcshell/test_assert.js
new file mode 100644
index 0000000000..42b46f08f8
--- /dev/null
+++ b/testing/modules/tests/xpcshell/test_assert.js
@@ -0,0 +1,491 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test cases borrowed and adapted from:
+// https://github.com/joyent/node/blob/6101eb184db77d0b11eb96e48744e57ecce4b73d/test/simple/test-assert.js
+// MIT license: http://opensource.org/licenses/MIT
+
+var { Assert } = ChromeUtils.importESModule(
+ "resource://testing-common/Assert.sys.mjs"
+);
+
+add_task(function test_basic_asserts() {
+ let assert = new Assert();
+
+ function makeBlock(f, ...args) {
+ return function () {
+ return f.apply(assert, args);
+ };
+ }
+
+ function protoCtrChain(o) {
+ let result = [];
+ while ((o = o.__proto__)) {
+ result.push(o.constructor);
+ }
+ return result.join();
+ }
+
+ function indirectInstanceOf(obj, cls) {
+ if (obj instanceof cls) {
+ return true;
+ }
+ let clsChain = protoCtrChain(cls.prototype);
+ let objChain = protoCtrChain(obj);
+ return objChain.slice(-clsChain.length) === clsChain;
+ }
+
+ assert.ok(
+ indirectInstanceOf(Assert.AssertionError.prototype, Error),
+ "Assert.AssertionError instanceof Error"
+ );
+
+ assert.throws(
+ makeBlock(assert.ok, false),
+ Assert.AssertionError,
+ "ok(false)"
+ );
+
+ assert.ok(true, "ok(true)");
+
+ assert.ok("test", "ok('test')");
+
+ assert.throws(
+ makeBlock(assert.equal, true, false),
+ Assert.AssertionError,
+ "equal"
+ );
+
+ assert.equal(null, null, "equal");
+
+ assert.equal(undefined, undefined, "equal");
+
+ assert.equal(null, undefined, "equal");
+
+ assert.equal(true, true, "equal");
+
+ assert.notEqual(true, false, "notEqual");
+
+ assert.throws(
+ makeBlock(assert.notEqual, true, true),
+ Assert.AssertionError,
+ "notEqual"
+ );
+
+ assert.throws(
+ makeBlock(assert.strictEqual, 2, "2"),
+ Assert.AssertionError,
+ "strictEqual"
+ );
+
+ assert.throws(
+ makeBlock(assert.strictEqual, null, undefined),
+ Assert.AssertionError,
+ "strictEqual"
+ );
+
+ assert.notStrictEqual(2, "2", "notStrictEqual");
+
+ // deepEquals joy!
+ // 7.2
+ assert.deepEqual(
+ new Date(2000, 3, 14),
+ new Date(2000, 3, 14),
+ "deepEqual date"
+ );
+ assert.deepEqual(new Date(NaN), new Date(NaN), "deepEqual invalid dates");
+
+ assert.throws(
+ makeBlock(assert.deepEqual, new Date(), new Date(2000, 3, 14)),
+ Assert.AssertionError,
+ "deepEqual date"
+ );
+
+ // 7.3
+ assert.deepEqual(/a/, /a/);
+ assert.deepEqual(/a/g, /a/g);
+ assert.deepEqual(/a/i, /a/i);
+ assert.deepEqual(/a/m, /a/m);
+ assert.deepEqual(/a/gim, /a/gim);
+ assert.throws(makeBlock(assert.deepEqual, /ab/, /a/), Assert.AssertionError);
+ assert.throws(makeBlock(assert.deepEqual, /a/g, /a/), Assert.AssertionError);
+ assert.throws(makeBlock(assert.deepEqual, /a/i, /a/), Assert.AssertionError);
+ assert.throws(makeBlock(assert.deepEqual, /a/m, /a/), Assert.AssertionError);
+ assert.throws(
+ makeBlock(assert.deepEqual, /a/gim, /a/im),
+ Assert.AssertionError
+ );
+
+ let re1 = /a/;
+ re1.lastIndex = 3;
+ assert.throws(makeBlock(assert.deepEqual, re1, /a/), Assert.AssertionError);
+
+ // 7.4
+ assert.deepEqual(4, "4", "deepEqual == check");
+ assert.deepEqual(true, 1, "deepEqual == check");
+ assert.throws(
+ makeBlock(assert.deepEqual, 4, "5"),
+ Assert.AssertionError,
+ "deepEqual == check"
+ );
+
+ // 7.5
+ // having the same number of owned properties && the same set of keys
+ assert.deepEqual({ a: 4 }, { a: 4 });
+ assert.deepEqual({ a: 4, b: "2" }, { a: 4, b: "2" });
+ assert.deepEqual([4], ["4"]);
+ assert.throws(
+ makeBlock(assert.deepEqual, { a: 4 }, { a: 4, b: true }),
+ Assert.AssertionError
+ );
+ assert.deepEqual(["a"], { 0: "a" });
+
+ let a1 = [1, 2, 3];
+ let a2 = [1, 2, 3];
+ a1.a = "test";
+ a1.b = true;
+ a2.b = true;
+ a2.a = "test";
+ assert.throws(
+ makeBlock(assert.deepEqual, Object.keys(a1), Object.keys(a2)),
+ Assert.AssertionError
+ );
+ assert.deepEqual(a1, a2);
+
+ let nbRoot = {
+ toString() {
+ return this.first + " " + this.last;
+ },
+ };
+
+ function nameBuilder(first, last) {
+ this.first = first;
+ this.last = last;
+ return this;
+ }
+ nameBuilder.prototype = nbRoot;
+
+ function nameBuilder2(first, last) {
+ this.first = first;
+ this.last = last;
+ return this;
+ }
+ nameBuilder2.prototype = nbRoot;
+
+ let nb1 = new nameBuilder("Ryan", "Dahl");
+ let nb2 = new nameBuilder2("Ryan", "Dahl");
+
+ assert.deepEqual(nb1, nb2);
+
+ nameBuilder2.prototype = Object;
+ nb2 = new nameBuilder2("Ryan", "Dahl");
+ assert.throws(makeBlock(assert.deepEqual, nb1, nb2), Assert.AssertionError);
+
+ // String literal + object
+ assert.throws(makeBlock(assert.deepEqual, "a", {}), Assert.AssertionError);
+
+ // Testing the throwing
+ function thrower(errorConstructor) {
+ throw new errorConstructor("test");
+ }
+ makeBlock(thrower, Assert.AssertionError);
+ makeBlock(thrower, Assert.AssertionError);
+
+ // the basic calls work
+ assert.throws(
+ makeBlock(thrower, Assert.AssertionError),
+ Assert.AssertionError,
+ "message"
+ );
+ assert.throws(
+ makeBlock(thrower, Assert.AssertionError),
+ Assert.AssertionError
+ );
+ assert.throws(
+ makeBlock(thrower, Assert.AssertionError),
+ Assert.AssertionError
+ );
+
+ // if not passing an error, catch all.
+ assert.throws(makeBlock(thrower, TypeError), TypeError);
+
+ // when passing a type, only catch errors of the appropriate type
+ let threw = false;
+ try {
+ assert.throws(makeBlock(thrower, TypeError), Assert.AssertionError);
+ } catch (e) {
+ threw = true;
+ assert.ok(e instanceof TypeError, "type");
+ }
+ assert.equal(
+ true,
+ threw,
+ "Assert.throws with an explicit error is eating extra errors",
+ Assert.AssertionError
+ );
+ threw = false;
+
+ function ifError(err) {
+ if (err) {
+ throw err;
+ }
+ }
+ assert.throws(function () {
+ ifError(new Error("test error"));
+ }, /test error/);
+
+ // make sure that validating using constructor really works
+ threw = false;
+ try {
+ assert.throws(function () {
+ throw new Error({});
+ }, Array);
+ } catch (e) {
+ threw = true;
+ }
+ assert.ok(threw, "wrong constructor validation");
+
+ // use a RegExp to validate error message
+ assert.throws(makeBlock(thrower, TypeError), /test/);
+
+ // use a fn to validate error object
+ assert.throws(makeBlock(thrower, TypeError), function (err) {
+ if (err instanceof TypeError && /test/.test(err)) {
+ return true;
+ }
+ return false;
+ });
+ // do the same with an arrow function
+ assert.throws(makeBlock(thrower, TypeError), err => {
+ if (err instanceof TypeError && /test/.test(err)) {
+ return true;
+ }
+ return false;
+ });
+
+ function testAssertionMessage(actual, expected) {
+ try {
+ assert.equal(actual, "");
+ } catch (e) {
+ assert.equal(
+ e.toString(),
+ ["AssertionError:", expected, "==", '""'].join(" ")
+ );
+ }
+ }
+ testAssertionMessage(undefined, '"undefined"');
+ testAssertionMessage(null, "null");
+ testAssertionMessage(true, "true");
+ testAssertionMessage(false, "false");
+ testAssertionMessage(0, "0");
+ testAssertionMessage(100, "100");
+ testAssertionMessage(NaN, '"NaN"');
+ testAssertionMessage(Infinity, '"Infinity"');
+ testAssertionMessage(-Infinity, '"-Infinity"');
+ testAssertionMessage("", '""');
+ testAssertionMessage("foo", '"foo"');
+ testAssertionMessage([], "[]");
+ testAssertionMessage([1, 2, 3], "[1,2,3]");
+ testAssertionMessage(/a/, '"/a/"');
+ testAssertionMessage(/abc/gim, '"/abc/gim"');
+ testAssertionMessage(function f() {}, '"function f() {}"');
+ testAssertionMessage({}, "{}");
+ testAssertionMessage({ a: undefined, b: null }, '{"a":"undefined","b":null}');
+ testAssertionMessage(
+ { a: NaN, b: Infinity, c: -Infinity },
+ '{"a":"NaN","b":"Infinity","c":"-Infinity"}'
+ );
+
+ // https://github.com/joyent/node/issues/2893
+ try {
+ assert.throws(function () {
+ ifError(null);
+ });
+ } catch (e) {
+ threw = true;
+ assert.equal(
+ e.message,
+ "Error: The 'expected' argument was not supplied to Assert.throws() - false == true"
+ );
+ }
+ assert.ok(threw);
+
+ // https://github.com/joyent/node/issues/5292
+ try {
+ assert.equal(1, 2);
+ } catch (e) {
+ assert.equal(e.toString().split("\n")[0], "AssertionError: 1 == 2");
+ }
+
+ try {
+ assert.equal(1, 2, "oh no");
+ } catch (e) {
+ assert.equal(e.toString().split("\n")[0], "AssertionError: oh no - 1 == 2");
+ }
+
+ // Need to JSON.stringify so that their length is > 128 characters.
+ let longArray0 = Array.from(Array(50), (v, i) => i);
+ let longArray1 = longArray0.concat([51]);
+ try {
+ assert.deepEqual(longArray0, longArray1);
+ } catch (e) {
+ let message = e.toString();
+ // Just check that they're both entirely present in the message
+ assert.ok(message.includes(JSON.stringify(longArray0)));
+ assert.ok(message.includes(JSON.stringify(longArray1)));
+ }
+
+ // Test XPCShell-test integration:
+ ok(true, "OK, this went well");
+ deepEqual(/a/g, /a/g, "deep equal should work on RegExp");
+ deepEqual(/a/gim, /a/gim, "deep equal should work on RegExp");
+ deepEqual(
+ { a: 4, b: "1" },
+ { b: "1", a: 4 },
+ "deep equal should work on regular Object"
+ );
+ deepEqual(a1, a2, "deep equal should work on Array with Object properties");
+
+ // Test robustness of reporting:
+ equal(
+ new Assert.AssertionError({
+ actual: {
+ toJSON() {
+ throw new Error("bam!");
+ },
+ },
+ expected: "foo",
+ operator: "=",
+ }).message,
+ '[object Object] = "foo"'
+ );
+
+ let message;
+ assert.greater(3, 2);
+ try {
+ assert.greater(2, 2);
+ } catch (e) {
+ message = e.toString().split("\n")[0];
+ }
+ assert.equal(message, "AssertionError: 2 > 2");
+
+ assert.greaterOrEqual(2, 2);
+ try {
+ assert.greaterOrEqual(1, 2);
+ } catch (e) {
+ message = e.toString().split("\n")[0];
+ }
+ assert.equal(message, "AssertionError: 1 >= 2");
+
+ assert.less(1, 2);
+ assert.throws(
+ () => assert.less(2, 2),
+ e => e == "AssertionError: 2 < 2"
+ );
+
+ assert.lessOrEqual(2, 2);
+ assert.throws(
+ () => assert.lessOrEqual(2, 1),
+ e => e == "AssertionError: 2 <= 1"
+ );
+
+ assert.throws(
+ () => assert.greater(NaN, 0),
+ e => e == "AssertionError: 'NaN' is not a number or date."
+ );
+
+ assert.throws(
+ () => assert.greater(0, NaN),
+ e => e == "AssertionError: 'NaN' is not a number or date."
+ );
+
+ let now = new Date();
+ let firefoxReleaseDate = new Date("2004-11-09");
+ assert.less(firefoxReleaseDate, now);
+ assert.throws(
+ () => assert.less(now, now),
+ e => e == `AssertionError: "${now.toJSON()}" < "${now.toJSON()}"`
+ );
+
+ assert.lessOrEqual(now, now);
+ assert.greaterOrEqual(now, now);
+ assert.throws(
+ () => assert.greaterOrEqual(firefoxReleaseDate, now),
+ e =>
+ e ==
+ `AssertionError: "${firefoxReleaseDate.toJSON()}" >= "${now.toJSON()}"`
+ );
+
+ // Invalid date:
+ assert.throws(
+ () => assert.greater(firefoxReleaseDate, new Date("invalid")),
+ e => e == "AssertionError: 'Invalid Date' is not a number or date."
+ );
+
+ /* ---- stringMatches ---- */
+ assert.stringMatches("hello world", /llo\s/);
+ assert.stringMatches("hello world", "llo\\s");
+ assert.throws(
+ () => assert.stringMatches("hello world", /foo/),
+ /^AssertionError: "hello world" matches "\/foo\/"/
+ );
+ assert.throws(
+ () => assert.stringMatches(5, /foo/),
+ /^AssertionError: Expected a string for lhs, but "5" isn't a string./
+ );
+ assert.throws(
+ () => assert.stringMatches("foo bar", "+"),
+ /^AssertionError: Expected a valid regular expression for rhs, but "\+" isn't one./
+ );
+
+ /* ---- stringContains ---- */
+ assert.stringContains("hello world", "llo");
+ assert.throws(
+ () => assert.stringContains(5, "foo"),
+ /^AssertionError: Expected a string for both lhs and rhs, but either "5" or "foo" is not a string./
+ );
+});
+
+add_task(async function test_rejects() {
+ let assert = new Assert();
+
+ // A helper function to test failures.
+ async function checkRejectsFails(err, expected) {
+ try {
+ await assert.rejects(Promise.reject(err), expected);
+ ok(false, "should have thrown");
+ } catch (ex) {
+ deepEqual(ex, err, "Assert.rejects threw the original unexpected error");
+ }
+ }
+
+ // A "throwable" error that's not an actual Error().
+ let SomeErrorLikeThing = function () {};
+
+ // The actual tests...
+
+ // An explicit error object:
+ // An instance to check against.
+ await assert.rejects(Promise.reject(new Error("oh no")), Error, "rejected");
+ // A regex to match against the message.
+ await assert.rejects(Promise.reject(new Error("oh no")), /oh no/, "rejected");
+
+ // Failure cases:
+ // An instance to check against that doesn't match.
+ await checkRejectsFails(new Error("something else"), SomeErrorLikeThing);
+ // A regex that doesn't match.
+ await checkRejectsFails(new Error("something else"), /oh no/);
+
+ // Check simple string messages.
+ await assert.rejects(Promise.reject("oh no"), /oh no/, "rejected");
+ // Wrong message.
+ await checkRejectsFails("something else", /oh no/);
+
+ // A non-rejection should also be an assertion failure:
+ try {
+ await assert.rejects(Promise.resolve(), /./, "ReSoLvEd");
+ ok(false, "should have rejected");
+ } catch (ex) {
+ deepEqual(ex.message, "Missing expected exception ReSoLvEd");
+ }
+});
diff --git a/testing/modules/tests/xpcshell/test_mockRegistrar.js b/testing/modules/tests/xpcshell/test_mockRegistrar.js
new file mode 100644
index 0000000000..de4224a092
--- /dev/null
+++ b/testing/modules/tests/xpcshell/test_mockRegistrar.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { MockRegistrar } = ChromeUtils.importESModule(
+ "resource://testing-common/MockRegistrar.sys.mjs"
+);
+
+function platformInfo(injectedValue) {
+ this.platformVersion = injectedValue;
+}
+
+platformInfo.prototype = {
+ platformVersion: "some version",
+ platformBuildID: "some id",
+ QueryInterface: ChromeUtils.generateQI(["nsIPlatformInfo"]),
+};
+
+add_test(function test_register() {
+ let localPlatformInfo = {
+ platformVersion: "local version",
+ platformBuildID: "local id",
+ QueryInterface: ChromeUtils.generateQI(["nsIPlatformInfo"]),
+ };
+
+ MockRegistrar.register("@mozilla.org/xre/app-info;1", localPlatformInfo);
+ Assert.equal(
+ Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
+ .platformVersion,
+ "local version"
+ );
+ run_next_test();
+});
+
+add_test(function test_register_with_arguments() {
+ MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, [
+ "override",
+ ]);
+ Assert.equal(
+ Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
+ .platformVersion,
+ "override"
+ );
+ run_next_test();
+});
+
+add_test(function test_register_twice() {
+ MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, [
+ "override",
+ ]);
+ Assert.equal(
+ Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
+ .platformVersion,
+ "override"
+ );
+
+ MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, [
+ "override again",
+ ]);
+ Assert.equal(
+ Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
+ .platformVersion,
+ "override again"
+ );
+ run_next_test();
+});
diff --git a/testing/modules/tests/xpcshell/test_structuredlog.js b/testing/modules/tests/xpcshell/test_structuredlog.js
new file mode 100644
index 0000000000..5288bbcbb3
--- /dev/null
+++ b/testing/modules/tests/xpcshell/test_structuredlog.js
@@ -0,0 +1,147 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+ const { StructuredLogger } = ChromeUtils.importESModule(
+ "resource://testing-common/StructuredLog.sys.mjs"
+ );
+
+ let testBuffer = [];
+
+ let appendBuffer = function (msg) {
+ testBuffer.push(JSON.stringify(msg));
+ };
+
+ let assertLastMsg = function (refData) {
+ // Check all fields in refData agree with those in the
+ // last message logged, and pop that message.
+ let lastMsg = JSON.parse(testBuffer.pop());
+ for (let field in refData) {
+ deepEqual(lastMsg[field], refData[field]);
+ }
+ // The logger should always set the source to the logger name.
+ equal(lastMsg.source, "test_log");
+ };
+
+ let logger = new StructuredLogger("test_log", appendBuffer);
+
+ // Test unstructured logging
+ logger.info("Test message");
+ assertLastMsg({
+ action: "log",
+ message: "Test message",
+ level: "INFO",
+ });
+
+ logger.info("Test message", { foo: "bar" });
+ assertLastMsg({
+ action: "log",
+ message: "Test message",
+ level: "INFO",
+ extra: { foo: "bar" },
+ });
+
+ // Test end / start actions
+ logger.testStart("aTest");
+ assertLastMsg({
+ test: "aTest",
+ action: "test_start",
+ });
+
+ logger.testEnd("aTest", "OK");
+ assertLastMsg({
+ test: "aTest",
+ action: "test_end",
+ status: "OK",
+ });
+
+ // A failed test populates the "expected" field.
+ logger.testStart("aTest");
+ logger.testEnd("aTest", "FAIL", "PASS");
+ assertLastMsg({
+ action: "test_end",
+ test: "aTest",
+ status: "FAIL",
+ expected: "PASS",
+ });
+
+ // A failed test populates the "expected" field.
+ logger.testStart("aTest");
+ logger.testEnd("aTest", "FAIL", "PASS", null, "Many\nlines\nof\nstack\n");
+ assertLastMsg({
+ action: "test_end",
+ test: "aTest",
+ status: "FAIL",
+ expected: "PASS",
+ stack: "Many\nlines\nof\nstack\n",
+ });
+
+ // Skipped tests don't log failures
+ logger.testStart("aTest");
+ logger.testEnd("aTest", "SKIP", "PASS");
+ ok(!JSON.parse(testBuffer[testBuffer.length - 1]).hasOwnProperty("expected"));
+ assertLastMsg({
+ action: "test_end",
+ test: "aTest",
+ status: "SKIP",
+ });
+
+ logger.testStatus("aTest", "foo", "PASS", "PASS", "Passed test");
+ ok(!JSON.parse(testBuffer[testBuffer.length - 1]).hasOwnProperty("expected"));
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "foo",
+ status: "PASS",
+ message: "Passed test",
+ });
+
+ logger.testStatus("aTest", "bar", "FAIL");
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "bar",
+ status: "FAIL",
+ expected: "PASS",
+ });
+
+ logger.testStatus(
+ "aTest",
+ "bar",
+ "FAIL",
+ "PASS",
+ null,
+ "Many\nlines\nof\nstack\n"
+ );
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "bar",
+ status: "FAIL",
+ expected: "PASS",
+ stack: "Many\nlines\nof\nstack\n",
+ });
+
+ // Skipped tests don't log failures
+ logger.testStatus("aTest", "baz", "SKIP");
+ ok(!JSON.parse(testBuffer[testBuffer.length - 1]).hasOwnProperty("expected"));
+ assertLastMsg({
+ action: "test_status",
+ test: "aTest",
+ subtest: "baz",
+ status: "SKIP",
+ });
+
+ // Suite start and end messages.
+ var ids = { aManifest: ["aTest"] };
+ logger.suiteStart(ids);
+ assertLastMsg({
+ action: "suite_start",
+ tests: { aManifest: ["aTest"] },
+ });
+
+ logger.suiteEnd();
+ assertLastMsg({
+ action: "suite_end",
+ });
+}
diff --git a/testing/modules/tests/xpcshell/xpcshell.toml b/testing/modules/tests/xpcshell/xpcshell.toml
new file mode 100644
index 0000000000..bca32fa174
--- /dev/null
+++ b/testing/modules/tests/xpcshell/xpcshell.toml
@@ -0,0 +1,8 @@
+[DEFAULT]
+head = ""
+
+["test_assert.js"]
+
+["test_mockRegistrar.js"]
+
+["test_structuredlog.js"]