Web Inspector: Audit: there should be a centralized place for reusable code
authordrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Mar 2019 18:56:28 +0000 (18:56 +0000)
committerdrousso@apple.com <drousso@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Mar 2019 18:56:28 +0000 (18:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195265
<rdar://problem/47040673>

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

* inspector/protocol/Audit.json:
Increment version.

Source/WebInspectorUI:

* UserInterface/Controllers/AuditManager.js:
(WI.AuditManager.prototype.async start):
(WI.AuditManager.prototype._topLevelTestForTest): Added.
(WI.AuditManager.prototype._topLevelTestForTest.walk): Added.

* UserInterface/Models/AuditTestBase.js:
(WI.AuditTestBase):
(WI.AuditTestBase.prototype.async setup): Added.
(WI.AuditTestBase.toJSON):

* UserInterface/Models/AuditTestCase.js:
(WI.AuditTestCase.async.fromPayload):
(WI.AuditTestCase.prototype.async run.async parseResponse):
Allow additional data to be passed back to the result's `data` for testing.

* UserInterface/Models/AuditTestGroup.js:
(WI.AuditTestGroup.async.fromPayload):

LayoutTests:

* inspector/audit/manager-start-setup.html: Added.
* inspector/audit/manager-start-setup-expected.txt: Added.
* inspector/model/auditTestCase.html:
* inspector/model/auditTestCase-expected.txt:
* inspector/model/auditTestGroup.html:
* inspector/model/auditTestGroup-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242808 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/audit/manager-start-setup-expected.txt [new file with mode: 0644]
LayoutTests/inspector/audit/manager-start-setup.html [new file with mode: 0644]
LayoutTests/inspector/model/auditTestCase-expected.txt
LayoutTests/inspector/model/auditTestCase.html
LayoutTests/inspector/model/auditTestGroup-expected.txt
LayoutTests/inspector/model/auditTestGroup.html
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/Audit.json
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js
Source/WebInspectorUI/UserInterface/Models/AuditTestBase.js
Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js
Source/WebInspectorUI/UserInterface/Models/AuditTestGroup.js

index 9c2fa6a..b2b1712 100644 (file)
@@ -1,3 +1,18 @@
+2019-03-12  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Audit: there should be a centralized place for reusable code
+        https://bugs.webkit.org/show_bug.cgi?id=195265
+        <rdar://problem/47040673>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/audit/manager-start-setup.html: Added.
+        * inspector/audit/manager-start-setup-expected.txt: Added.
+        * inspector/model/auditTestCase.html:
+        * inspector/model/auditTestCase-expected.txt:
+        * inspector/model/auditTestGroup.html:
+        * inspector/model/auditTestGroup-expected.txt:
+
 2019-03-12  Daniel Bates  <dabates@apple.com>
 
         [iOS] Add test to ensure that a web page can prevent the default for Command + A
diff --git a/LayoutTests/inspector/audit/manager-start-setup-expected.txt b/LayoutTests/inspector/audit/manager-start-setup-expected.txt
new file mode 100644 (file)
index 0000000..0e72cbd
--- /dev/null
@@ -0,0 +1,20 @@
+Tests for the AuditManager.prototype.start functionality.
+
+
+== Running test suite: AuditManager.prototype.start
+-- Running test case: AuditManager.prototype.start.SyncSetup
+PASS: The setup function should have set __test to 42.
+
+-- Running test case: AuditManager.prototype.start.AsyncSetup
+PASS: The setup function should have set __test to 42.
+
+-- Running test case: AuditManager.prototype.start.SubLevelSetup
+PASS: The setup function should have set __test to undefined.
+
+-- Running test case: AuditManager.prototype.start.OverriddenSetup
+PASS: The setup function should have set __test to B.
+
+-- Running test case: AuditManager.prototype.start.MultipleTopLevel
+PASS: The setup function should have set __test to A.
+PASS: The setup function should have set __test to B.
+
diff --git a/LayoutTests/inspector/audit/manager-start-setup.html b/LayoutTests/inspector/audit/manager-start-setup.html
new file mode 100644 (file)
index 0000000..88c22d1
--- /dev/null
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+
+function test()
+{
+    const auditTestString = (function() {
+        return {
+            level: "pass",
+            __test: WebInspectorAudit.__test,
+        };
+    }).toString();
+
+    async function wrapTest(audit, expected, {getResultCallback} = {}) {
+        WI.auditManager._addTest(audit);
+
+        let [result] = await WI.auditManager.start([audit]);
+        if (getResultCallback)
+            result = getResultCallback(result);
+
+        InspectorTest.assert(result.didPass, "The test should pass.");
+        InspectorTest.assert(!result.data.errors, "There should be no errors.");
+        InspectorTest.expectEqual(result.data.__test.value, expected, `The setup function should have set __test to ${expected}.`);
+
+        WI.auditManager.removeTest(audit);
+    }
+
+    let suite = InspectorTest.createAsyncSuite("AuditManager.prototype.start");
+
+    suite.addTestCase({
+        name: "AuditManager.prototype.start.SyncSetup",
+        description: "Check that the setup of an audit is actually run.",
+        async test() {
+            const setup = (function() {
+                WebInspectorAudit.__test = 42;
+            }).toString();
+
+            let audit = new WI.AuditTestCase("AuditManager.prototype.start.SyncSetup", auditTestString, {setup});
+
+            await wrapTest(audit, 42);
+        },
+    });
+
+    suite.addTestCase({
+        name: "AuditManager.prototype.start.AsyncSetup",
+        description: "Check that the setup of an audit can be asynchronous.",
+        async test() {
+            const setup = (async function() {
+                await new Promise((resolve, reject) => {
+                    setTimeout(resolve, 10);
+                });
+
+                WebInspectorAudit.__test = 42;
+            }).toString();
+
+            let audit = new WI.AuditTestCase("AuditManager.prototype.start.AsyncSetup", auditTestString, {setup});
+
+            await wrapTest(audit, 42);
+        },
+    });
+
+    suite.addTestCase({
+        name: "AuditManager.prototype.start.SubLevelSetup",
+        description: "Check that the setup of a non-top-level audit is not run.",
+        async test() {
+            const setup = (function() {
+                WebInspectorAudit.__test = 42;
+            }).toString();
+
+            let audit = new WI.AuditTestGroup("AuditManager.prototype.start.SubLevelSetup.Group", [
+                new WI.AuditTestCase("AuditManager.prototype.start.SubLevelSetup.Test", auditTestString, {setup}),
+            ]);
+
+            await wrapTest(audit, undefined, {
+                getResultCallback(result) {
+                    return result.results[0];
+                },
+            });
+        },
+    });
+
+    suite.addTestCase({
+        name: "AuditManager.prototype.start.OverriddenSetup",
+        description: "Check that only the setup of top-level audits is run.",
+        async test() {
+            const setupA = (function() {
+                if (!WebInspectorAudit.__test)
+                    WebInspectorAudit.__test = "";
+                WebInspectorAudit.__test += "A";
+            }).toString();
+
+            const setupB = (function() {
+                if (!WebInspectorAudit.__test)
+                    WebInspectorAudit.__test = "";
+                WebInspectorAudit.__test += "B";
+            }).toString();
+
+            let audit = new WI.AuditTestGroup("AuditManager.prototype.start.OverriddenLevelSetup.Group", [
+                new WI.AuditTestCase("AuditManager.prototype.start.OverriddenLevelSetup.Test", auditTestString, {setup: setupA}),
+            ], {setup: setupB});
+
+            await wrapTest(audit, "B", {
+                getResultCallback(result) {
+                    return result.results[0];
+                },
+            });
+        },
+    });
+
+    suite.addTestCase({
+        name: "AuditManager.prototype.start.MultipleTopLevel",
+        description: "Test that a new WebInspectorAudit object is created for each setup call.",
+        async test() {
+            const setupA = (function() {
+                if (!WebInspectorAudit.__test)
+                    WebInspectorAudit.__test = "";
+                WebInspectorAudit.__test += "A";
+            }).toString();
+
+            let auditA = new WI.AuditTestCase("AuditManager.prototype.start.MultipleTopLevel.A", auditTestString, {setup: setupA});
+
+            await wrapTest(auditA, "A");
+
+            const setupB = (function() {
+                if (!WebInspectorAudit.__test)
+                    WebInspectorAudit.__test = "";
+                WebInspectorAudit.__test += "B";
+            }).toString();
+
+            let auditB = new WI.AuditTestCase("AuditManager.prototype.start.MultipleTopLevel.B", auditTestString, {setup: setupB});
+
+            await wrapTest(auditB, "B");
+        },
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+    <p>Tests for the AuditManager.prototype.start functionality.</p>
+</body>
+</html>
index 2d20ab4..984ad20 100644 (file)
@@ -23,11 +23,12 @@ null
 
 -- Running test case: AuditTestCase.fromPayload.validWithInvalidOptionals
 WARN: Audit Warning: "validWithInvalidOptionals test name" has a non-string "description" value
+WARN: Audit Warning: "validWithInvalidOptionals test name" has a non-string "setup" value
 WARN: Audit Warning: "validWithInvalidOptionals test name" is too new to run in this Web Inspector
 {
   "type": "test-case",
   "name": "validWithInvalidOptionals test name",
-  "supports": 2,
+  "supports": 3,
   "test": "validWithInvalidOptionals test function"
 }
 
@@ -36,7 +37,8 @@ WARN: Audit Warning: "validWithInvalidOptionals test name" is too new to run in
   "type": "test-case",
   "name": "validWithValidOptionals test name",
   "description": "validWithValidOptionals test description",
-  "supports": 0,
+  "supports": 1,
+  "setup": "validWithValidOptionals test setup",
   "test": "validWithValidOptionals test function"
 }
 
index ebcf879..915e637 100644 (file)
@@ -53,6 +53,7 @@ function test()
                 name: "validWithInvalidOptionals test name",
                 description: null,
                 supports: WI.AuditTestBase.Version + 1,
+                setup: null,
                 test: "validWithInvalidOptionals test function",
             },
         },
@@ -63,6 +64,7 @@ function test()
                 name: "validWithValidOptionals test name",
                 description: "validWithValidOptionals test description",
                 supports: WI.AuditTestBase.Version - 1,
+                setup: "validWithValidOptionals test setup",
                 test: "validWithValidOptionals test function",
             },
         },
index 5e2629e..bebb554 100644 (file)
@@ -35,18 +35,20 @@ null
 
 -- Running test case: AuditTestGroup.fromPayload.validWithInvalidOptionals
 WARN: Audit Warning: "validWithInvalidOptionals test name" has a non-string "description" value
+WARN: Audit Warning: "validWithInvalidOptionals test name" has a non-string "setup" value
 WARN: Audit Warning: "validWithInvalidOptionals test name" is too new to run in this Web Inspector
 WARN: Audit Warning: "validWithInvalidOptionals group name" has a non-string "description" value
+WARN: Audit Warning: "validWithInvalidOptionals group name" has a non-string "setup" value
 WARN: Audit Warning: "validWithInvalidOptionals group name" is too new to run in this Web Inspector
 {
   "type": "test-group",
   "name": "validWithInvalidOptionals group name",
-  "supports": 2,
+  "supports": 3,
   "tests": [
     {
       "type": "test-case",
       "name": "validWithInvalidOptionals test name",
-      "supports": 3,
+      "supports": 4,
       "test": "validWithInvalidOptionals test function"
     }
   ]
@@ -57,13 +59,15 @@ WARN: Audit Warning: "validWithInvalidOptionals group name" is too new to run in
   "type": "test-group",
   "name": "validWithValidOptionals group name",
   "description": "validWithValidOptionals group description",
-  "supports": 0,
+  "supports": 1,
+  "setup": "validWithValidOptionals group setup",
   "tests": [
     {
       "type": "test-case",
       "name": "validWithValidOptionals test name",
       "description": "validWithValidOptionals test description",
-      "supports": -1,
+      "supports": 0,
+      "setup": "validWithValidOptionals test setup",
       "test": "validWithValidOptionals test function"
     }
   ]
@@ -74,19 +78,22 @@ WARN: Audit Warning: "validWithInvalidOptionals group name" is too new to run in
   "type": "test-group",
   "name": "validNested group name",
   "description": "validNested group description",
-  "supports": 0,
+  "supports": 1,
+  "setup": "validNested group setup",
   "tests": [
     {
       "type": "test-group",
       "name": "validNested nested group name",
       "description": "validNested nested group description",
-      "supports": -1,
+      "supports": 0,
+      "setup": "validNested nested group setup",
       "tests": [
         {
           "type": "test-case",
           "name": "validNested nested test name",
           "description": "validNested nested test description",
-          "supports": -2,
+          "supports": -1,
+          "setup": "validNested nested test setup",
           "test": "validNested nested test function"
         }
       ]
@@ -95,7 +102,8 @@ WARN: Audit Warning: "validWithInvalidOptionals group name" is too new to run in
       "type": "test-case",
       "name": "validNested test name",
       "description": "validNested test description",
-      "supports": -3,
+      "supports": -2,
+      "setup": "validNested test setup",
       "test": "validNested test function"
     }
   ]
index dc2193f..04a1c7f 100644 (file)
@@ -77,12 +77,14 @@ function test()
                 name: "validWithInvalidOptionals group name",
                 description: null,
                 supports: WI.AuditTestBase.Version + 1,
+                setup: null,
                 tests: [
                     {
                         type: WI.AuditTestCase.TypeIdentifier,
                         name: "validWithInvalidOptionals test name",
                         description: null,
                         supports: WI.AuditTestBase.Version + 2,
+                        setup: null,
                         test: "validWithInvalidOptionals test function",
                     },
                 ],
@@ -95,12 +97,14 @@ function test()
                 name: "validWithValidOptionals group name",
                 description: "validWithValidOptionals group description",
                 supports: WI.AuditTestBase.Version - 1,
+                setup: "validWithValidOptionals group setup",
                 tests: [
                     {
                         type: WI.AuditTestCase.TypeIdentifier,
                         name: "validWithValidOptionals test name",
                         description: "validWithValidOptionals test description",
                         supports: WI.AuditTestBase.Version - 2,
+                        setup: "validWithValidOptionals test setup",
                         test: "validWithValidOptionals test function",
                     },
                 ],
@@ -113,18 +117,21 @@ function test()
                 name: "validNested group name",
                 description: "validNested group description",
                 supports: WI.AuditTestBase.Version - 1,
+                setup: "validNested group setup",
                 tests: [
                     {
                         type: WI.AuditTestGroup.TypeIdentifier,
                         name: "validNested nested group name",
                         description: "validNested nested group description",
                         supports: WI.AuditTestBase.Version - 2,
+                        setup: "validNested nested group setup",
                         tests: [
                             {
                                 type: WI.AuditTestCase.TypeIdentifier,
                                 name: "validNested nested test name",
                                 description: "validNested nested test description",
                                 supports: WI.AuditTestBase.Version - 3,
+                                setup: "validNested nested test setup",
                                 test: "validNested nested test function",
                             },
                         ],
@@ -134,6 +141,7 @@ function test()
                         name: "validNested test name",
                         description: "validNested test description",
                         supports: WI.AuditTestBase.Version - 4,
+                        setup: "validNested test setup",
                         test: "validNested test function",
                     },
                 ],
index e7795e4..079165f 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-12  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Audit: there should be a centralized place for reusable code
+        https://bugs.webkit.org/show_bug.cgi?id=195265
+        <rdar://problem/47040673>
+
+        Reviewed by Joseph Pecoraro.
+
+        * inspector/protocol/Audit.json:
+        Increment version.
+
 2019-03-12  Robin Morisset  <rmorisset@apple.com>
 
         blocksInPreOrder and blocksInPostOrder should reserve the right capacity for their result vector
index 9f6a6bb..589d8cc 100644 (file)
@@ -1,7 +1,7 @@
 {
     "domain": "Audit",
     "description": "",
-    "version": 1,
+    "version": 2,
     "commands": [
         {
             "name": "setup",
index 413e3b9..9e029ba 100644 (file)
@@ -1,3 +1,29 @@
+2019-03-12  Devin Rousso  <drousso@apple.com>
+
+        Web Inspector: Audit: there should be a centralized place for reusable code
+        https://bugs.webkit.org/show_bug.cgi?id=195265
+        <rdar://problem/47040673>
+
+        Reviewed by Joseph Pecoraro.
+
+        * UserInterface/Controllers/AuditManager.js:
+        (WI.AuditManager.prototype.async start):
+        (WI.AuditManager.prototype._topLevelTestForTest): Added.
+        (WI.AuditManager.prototype._topLevelTestForTest.walk): Added.
+
+        * UserInterface/Models/AuditTestBase.js:
+        (WI.AuditTestBase):
+        (WI.AuditTestBase.prototype.async setup): Added.
+        (WI.AuditTestBase.toJSON):
+
+        * UserInterface/Models/AuditTestCase.js:
+        (WI.AuditTestCase.async.fromPayload):
+        (WI.AuditTestCase.prototype.async run.async parseResponse):
+        Allow additional data to be passed back to the result's `data` for testing.
+
+        * UserInterface/Models/AuditTestGroup.js:
+        (WI.AuditTestGroup.async.fromPayload):
+
 2019-03-12  Joseph Pecoraro  <pecoraro@apple.com>
 
         Web Inspector: Timelines - Improve handling of past recordings (readonly)
index f808b27..b8e95b6 100644 (file)
@@ -127,7 +127,7 @@ WI.AuditManager = class AuditManager extends WI.Object
     {
         console.assert(this._runningState === WI.AuditManager.RunningState.Inactive);
         if (this._runningState !== WI.AuditManager.RunningState.Inactive)
-            return;
+            return null;
 
         if (tests && tests.length)
             tests = tests.filter((test) => typeof test === "object" && test instanceof WI.AuditTestBase);
@@ -136,7 +136,7 @@ WI.AuditManager = class AuditManager extends WI.Object
 
         console.assert(tests.length);
         if (!tests.length)
-            return;
+            return null;
 
         let mainResource = WI.networkManager.mainFrame.mainResource;
 
@@ -154,6 +154,11 @@ WI.AuditManager = class AuditManager extends WI.Object
             if (InspectorBackend.domains.Audit)
                 await AuditAgent.setup();
 
+            let topLevelTest = this._topLevelTestForTest(test);
+            console.assert(topLevelTest || window.InspectorTest, "No matching top-level test found", test);
+            if (topLevelTest)
+                await topLevelTest.setup();
+
             await test.start();
 
             if (InspectorBackend.domains.Audit)
@@ -172,6 +177,8 @@ WI.AuditManager = class AuditManager extends WI.Object
             for (let test of this._tests)
                 test.clearResult();
         }
+
+        return this._results.lastValue === result ? result : null;
     }
 
     stop()
@@ -287,6 +294,28 @@ WI.AuditManager = class AuditManager extends WI.Object
         });
     }
 
+    _topLevelTestForTest(test)
+    {
+        function walk(group) {
+            if (group === test)
+                return true;
+            if (group instanceof WI.AuditTestGroup) {
+                for (let subtest of group.tests) {
+                    if (walk(subtest))
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        for (let topLevelTest of this._tests) {
+            if (walk(topLevelTest))
+                return topLevelTest;
+        }
+
+        return null;
+    }
+
     _handleFrameMainResourceDidChange(event)
     {
         if (!event.target.isMainFrame())
index 0a2b5ca..2ad5110 100644 (file)
 
 WI.AuditTestBase = class AuditTestBase extends WI.Object
 {
-    constructor(name, {description, supports, disabled} = {})
+    constructor(name, {description, supports, setup, disabled} = {})
     {
         console.assert(typeof name === "string");
         console.assert(!description || typeof description === "string");
         console.assert(supports === undefined || typeof supports === "number");
+        console.assert(!setup || typeof setup === "string");
         console.assert(disabled === undefined || typeof disabled === "boolean");
 
         super();
@@ -40,6 +41,7 @@ WI.AuditTestBase = class AuditTestBase extends WI.Object
         this._name = name;
         this._description = description || null;
         this._supports = supports;
+        this._setup = setup || null;
 
         this._supported = true;
         if (typeof this._supports === "number") {
@@ -101,6 +103,45 @@ WI.AuditTestBase = class AuditTestBase extends WI.Object
         this.dispatchEventToListeners(WI.AuditTestBase.Event.DisabledChanged);
     }
 
+    async setup()
+    {
+        if (!this._setup)
+            return;
+
+        let agentCommandFunction = null;
+        let agentCommandArguments = {};
+        if (InspectorBackend.domains.Audit) {
+            agentCommandFunction = AuditAgent.run;
+            agentCommandArguments.test = this._setup;
+        } else {
+            agentCommandFunction = RuntimeAgent.evaluate;
+            agentCommandArguments.expression = `(function() { "use strict"; return eval(\`(${this._setup.replace(/`/g, "\\`")})\`)(); })()`;
+            agentCommandArguments.objectGroup = "audit";
+            agentCommandArguments.doNotPauseOnExceptionsAndMuteConsole = true;
+        }
+
+        try {
+            let response = await agentCommandFunction.invoke(agentCommandArguments);
+
+            if (response.result.type === "object" && response.result.className === "Promise") {
+                if (WI.RuntimeManager.supportsAwaitPromise())
+                    response = await RuntimeAgent.awaitPromise(response.result.objectId);
+                else {
+                    response = null;
+                    WI.AuditManager.synthesizeError(WI.UIString("Async audits are not supported."));
+                }
+            }
+
+            if (response) {
+                let remoteObject = WI.RemoteObject.fromPayload(response.result, WI.mainTarget);
+                if (response.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
+                    WI.AuditManager.synthesizeError(remoteObject.description);
+            }
+        } catch (error) {
+            WI.AuditManager.synthesizeError(error.message);
+        }
+    }
+
     async start()
     {
         // Called from WI.AuditManager.
@@ -171,6 +212,8 @@ WI.AuditTestBase = class AuditTestBase extends WI.Object
             json.description = this._description;
         if (typeof this._supports === "number")
             json.supports = this._supports;
+        if (this._setup)
+            json.setup = this._setup;
         if (key === WI.ObjectStore.toJSONSymbol)
             json.disabled = this.disabled;
         return json;
@@ -185,7 +228,7 @@ WI.AuditTestBase = class AuditTestBase extends WI.Object
 };
 
 // Keep this in sync with Inspector::Protocol::Audit::VERSION.
-WI.AuditTestBase.Version = 1;
+WI.AuditTestBase.Version = 2;
 
 WI.AuditTestBase.Event = {
     Completed: "audit-test-base-completed",
index 85f1954..61b0883 100644 (file)
@@ -66,6 +66,11 @@ WI.AuditTestCase = class AuditTestCase extends WI.AuditTestBase
         else if ("supports" in payload)
             WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-number \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("supports")));
 
+        if (typeof payload.setup === "string")
+            options.setup = payload.setup;
+        else if ("setup" in payload)
+            WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("setup")));
+
         if (typeof payload.disabled === "boolean")
             options.disabled = payload.disabled;
 
@@ -235,6 +240,9 @@ WI.AuditTestCase = class AuditTestCase extends WI.AuditTestBase
 
                     addError(item.value.description);
                 });
+
+                if (window.InspectorTest && properties.__test)
+                    data.__test = properties.__test.value;
             } else
                 addError(WI.UIString("Return value is not an object, string, or boolean"));
         }
index ef38078..c7f2af8 100644 (file)
@@ -106,6 +106,11 @@ WI.AuditTestGroup = class AuditTestGroup extends WI.AuditTestBase
         else if ("supports" in payload)
             WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-number \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("supports")));
 
+        if (typeof payload.setup === "string")
+            options.setup = payload.setup;
+        else if ("setup" in payload)
+            WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("setup")));
+
         if (typeof payload.disabled === "boolean")
             options.disabled = payload.disabled;