⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 237644 in webkit


Ignore:
Timestamp:
Oct 31, 2018, 11:25:54 AM (8 years ago)
Author:
Devin Rousso
Message:

Web Inspector: Audit: show metadata for results
https://bugs.webkit.org/show_bug.cgi?id=190853
<rdar://problem/45527623>

Reviewed by Brian Burg.

Source/WebInspectorUI:

  • UserInterface/Models/AuditTestCase.js:

(WI.AuditTestCase.prototype.async run):
Capture timestamps around the RunetimeAgent.evaluate call, as well as the URL of the page.

  • UserInterface/Models/AuditTestCaseResult.js:

(WI.AuditTestCaseResult):
(WI.AuditTestCaseResult.fromPayload):
(WI.AuditTestCaseResult.prototype.get metadata): Added.
(WI.AuditTestCaseResult.prototype.toJSON):

  • UserInterface/Views/AuditTestCaseContentView.js:

(WI.AuditTestCaseContentView.prototype.initialLayout):
(WI.AuditTestCaseContentView.prototype.layout):

  • UserInterface/Views/AuditTestCaseContentView.css:

(.content-view.audit-test-case > header h1): Added.
(.content-view.audit-test-case > header h1 > img): Added.
(.content-view.audit-test-case > header > .metadata): Added.
(.content-view.audit-test-case > header > .metadata > .source > time): Added.
(.content-view.audit-test-case > header > .metadata > .source > a): Added.
(.content-view.audit-test-case > header > .metadata > .duration): Added.
(.content-view.audit-test-case > header > h1): Deleted.
(.content-view.audit-test-case > header > h1 > img): Deleted.
Display any metadata information where the WI.ScopeBar is for WI.AuditTestGroupContentViews.

  • UserInterface/Views/AuditTestContentView.css:

(.content-view.audit-test > header):
(.content-view.audit-test > header > .information): Added.

  • UserInterface/Views/AuditTestGroupContentView.css:

(.content-view.audit-test-group > header):
(.content-view.audit-test-group > header > .percentage-pass):
(.content-view.audit-test-group > header > .information): Deleted.
Move common CSS rules to common parent class.

  • UserInterface/Base/Utilities.js:

LayoutTests:

  • inspector/model/auditTestCaseResult-expected.txt:
  • inspector/model/auditTestCaseResult.html:
  • inspector/model/auditTestGroupResult-expected.txt:
  • inspector/model/auditTestGroupResult.html:
  • inspector/unit-tests/string-utilities-expected.txt:
  • inspector/unit-tests/string-utilities.html:
Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r237643 r237644  
     12018-10-31  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: Audit: show metadata for results
     4        https://bugs.webkit.org/show_bug.cgi?id=190853
     5        <rdar://problem/45527623>
     6
     7        Reviewed by Brian Burg.
     8
     9        * inspector/model/auditTestCaseResult-expected.txt:
     10        * inspector/model/auditTestCaseResult.html:
     11        * inspector/model/auditTestGroupResult-expected.txt:
     12        * inspector/model/auditTestGroupResult.html:
     13        * inspector/unit-tests/string-utilities-expected.txt:
     14        * inspector/unit-tests/string-utilities.html:
     15
    1162018-10-31  Eric Carlson  <eric.carlson@apple.com>
    217
  • trunk/LayoutTests/inspector/model/auditTestCaseResult-expected.txt

    r237613 r237644  
    5353      "validWithValidSubOptionals test result error"
    5454    ]
     55  },
     56  "metadata": {
     57    "startTimestamp": "0001-01-01T00:00:00.000Z",
     58    "endTimestamp": "0002-01-01T00:00:00.000Z",
     59    "url": "validWithValidSubOptionals test result url"
    5560  }
    5661}
  • trunk/LayoutTests/inspector/model/auditTestCaseResult.html

    r237613 r237644  
    5555                level: WI.AuditTestCaseResult.Level.Pass,
    5656                data: null,
     57                metadata: null,
    5758            },
    5859        },
     
    6869                    domAttributes: null,
    6970                    errors: null,
     71                },
     72                metadata: {
     73                    startTimestamp: null,
     74                    endTimestamp: null,
     75                    url: null,
    7076                },
    7177            },
     
    8389                    errors: ["validWithValidSubOptionals test result error"],
    8490                },
     91                metadata: {
     92                    startTimestamp: "1",
     93                    endTimestamp: "2",
     94                    url: "validWithValidSubOptionals test result url",
     95                },
    8596            },
    8697        },
  • trunk/LayoutTests/inspector/model/auditTestGroupResult-expected.txt

    r237613 r237644  
    6868          "validWithValidOptionals test result error"
    6969        ]
     70      },
     71      "metadata": {
     72        "startTimestamp": "0001-01-01T00:00:00.000Z",
     73        "endTimestamp": "0002-01-01T00:00:00.000Z",
     74        "url": "validWithValidOptionals test result url"
    7075      }
    7176    }
     
    99104              "validNested nested test result error"
    100105            ]
     106          },
     107          "metadata": {
     108            "startTimestamp": "0001-01-01T00:00:00.000Z",
     109            "endTimestamp": "0002-01-01T00:00:00.000Z",
     110            "url": "validNested nested test result url"
    101111          }
    102112        }
     
    118128          "validNested test result error"
    119129        ]
     130      },
     131      "metadata": {
     132        "startTimestamp": "0003-01-01T00:00:00.000Z",
     133        "endTimestamp": "0004-01-01T00:00:00.000Z",
     134        "url": "validNested test result url"
    120135      }
    121136    }
  • trunk/LayoutTests/inspector/model/auditTestGroupResult.html

    r237613 r237644  
    8484                        level: WI.AuditTestCaseResult.Level.Pass,
    8585                        data: null,
     86                        metadata: null,
    8687                    },
    8788                ],
     
    104105                            domAttributes: ["validWithValidOptionals test result domAttribute"],
    105106                            errors: ["validWithValidOptionals test result error"],
     107                        },
     108                        metadata: {
     109                            startTimestamp: "1",
     110                            endTimestamp: "2",
     111                            url: "validWithValidOptionals test result url",
    106112                        },
    107113                    },
     
    131137                                    errors: ["validNested nested test result error"],
    132138                                },
     139                                metadata: {
     140                                    startTimestamp: "1",
     141                                    endTimestamp: "2",
     142                                    url: "validNested nested test result url",
     143                                },
    133144                            },
    134145                        ],
     
    143154                            domAttributes: ["validNested test result domAttribute"],
    144155                            errors: ["validNested test result error"],
     156                        },
     157                        metadata: {
     158                            startTimestamp: "3",
     159                            endTimestamp: "4",
     160                            url: "validNested test result url",
    145161                        },
    146162                    },
  • trunk/LayoutTests/inspector/unit-tests/string-utilities-expected.txt

    r230021 r237644  
    4747PASS: Last line of an empty string is the same empty string.
    4848
     49-- Running test case: String.prototype.truncateStart
     50PASS: String stays the same.
     51PASS: Ellipsis is inserted before the third character.
     52PASS: Ellipsis is inserted before the fourth character.
     53
    4954-- Running test case: String.prototype.truncateMiddle
    5055PASS: String stays the same.
     
    5459-- Running test case: String.prototype.truncateEnd
    5560PASS: String stays the same.
    56 PASS: Ellipsis is inserted in the middle.
     61PASS: Ellipsis is inserted after the fourth character.
    5762PASS: Ellipsis is inserted after the third character.
    5863
  • trunk/LayoutTests/inspector/unit-tests/string-utilities.html

    r230021 r237644  
    8080
    8181    suite.addTestCase({
     82        name: "String.prototype.truncateStart",
     83        test() {
     84            const ellipsis = "\u2026";
     85            InspectorTest.expectEqual("abcdef".truncateStart(6), "abcdef", "String stays the same.");
     86            InspectorTest.expectEqual("abcdef".truncateStart(5), ellipsis + "cdef", "Ellipsis is inserted before the third character.");
     87            InspectorTest.expectEqual("abcdef".truncateStart(4), ellipsis + "def", "Ellipsis is inserted before the fourth character.");
     88            return true;
     89        }
     90    });
     91
     92    suite.addTestCase({
    8293        name: "String.prototype.truncateMiddle",
    8394        test() {
     
    95106            const ellipsis = "\u2026";
    96107            InspectorTest.expectEqual("abcdef".truncateEnd(6), "abcdef", "String stays the same.");
    97             InspectorTest.expectEqual("abcdef".truncateEnd(5), "abcd" + ellipsis, "Ellipsis is inserted in the middle.");
     108            InspectorTest.expectEqual("abcdef".truncateEnd(5), "abcd" + ellipsis, "Ellipsis is inserted after the fourth character.");
    98109            InspectorTest.expectEqual("abcdef".truncateEnd(4), "abc" + ellipsis, "Ellipsis is inserted after the third character.");
    99110            return true;
  • trunk/Source/WebInspectorUI/ChangeLog

    r237613 r237644  
     12018-10-31  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: Audit: show metadata for results
     4        https://bugs.webkit.org/show_bug.cgi?id=190853
     5        <rdar://problem/45527623>
     6
     7        Reviewed by Brian Burg.
     8
     9        * UserInterface/Models/AuditTestCase.js:
     10        (WI.AuditTestCase.prototype.async run):
     11        Capture timestamps around the `RunetimeAgent.evaluate` call, as well as the URL of the page.
     12
     13        * UserInterface/Models/AuditTestCaseResult.js:
     14        (WI.AuditTestCaseResult):
     15        (WI.AuditTestCaseResult.fromPayload):
     16        (WI.AuditTestCaseResult.prototype.get metadata): Added.
     17        (WI.AuditTestCaseResult.prototype.toJSON):
     18
     19        * UserInterface/Views/AuditTestCaseContentView.js:
     20        (WI.AuditTestCaseContentView.prototype.initialLayout):
     21        (WI.AuditTestCaseContentView.prototype.layout):
     22        * UserInterface/Views/AuditTestCaseContentView.css:
     23        (.content-view.audit-test-case > header h1): Added.
     24        (.content-view.audit-test-case > header h1 > img): Added.
     25        (.content-view.audit-test-case > header > .metadata): Added.
     26        (.content-view.audit-test-case > header > .metadata > .source > time): Added.
     27        (.content-view.audit-test-case > header > .metadata > .source > a): Added.
     28        (.content-view.audit-test-case > header > .metadata > .duration): Added.
     29        (.content-view.audit-test-case > header > h1): Deleted.
     30        (.content-view.audit-test-case > header > h1 > img): Deleted.
     31        Display any metadata information where the `WI.ScopeBar` is for `WI.AuditTestGroupContentView`s.
     32
     33        * UserInterface/Views/AuditTestContentView.css:
     34        (.content-view.audit-test > header):
     35        (.content-view.audit-test > header > .information): Added.
     36        * UserInterface/Views/AuditTestGroupContentView.css:
     37        (.content-view.audit-test-group > header):
     38        (.content-view.audit-test-group > header > .percentage-pass):
     39        (.content-view.audit-test-group > header > .information): Deleted.
     40        Move common CSS rules to common parent class.
     41
     42        * UserInterface/Base/Utilities.js:
     43
    1442018-10-30  Devin Rousso  <drousso@apple.com>
    245
  • trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js

    r237613 r237644  
    583583});
    584584
     585Object.defineProperty(String.prototype, "truncateStart",
     586{
     587    value(maxLength)
     588    {
     589        "use strict";
     590
     591        if (this.length <= maxLength)
     592            return this;
     593        return ellipsis + this.substr(this.length - maxLength + 1);
     594    }
     595});
     596
    585597Object.defineProperty(String.prototype, "truncateMiddle",
    586598{
  • trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCase.js

    r237613 r237644  
    7878        let level = null;
    7979        let data = {};
     80        let metadata = {
     81            url: WI.networkManager.mainFrame.url,
     82            startTimestamp: null,
     83            endTimestamp: null,
     84        };
    8085
    8186        function setLevel(newLevel) {
     
    101106        }
    102107
     108        let evaluateArguments = {
     109            expression: `(function() { "use strict"; return eval(${this._test})(); })()`,
     110            objectGroup: "audit",
     111            doNotPauseOnExceptionsAndMuteConsole: true,
     112        };
     113
    103114        try {
    104             let {result, wasThrown} = await RuntimeAgent.evaluate.invoke({
    105                 expression: `(function() { "use strict"; return eval(${this._test})(); })()`,
    106                 objectGroup: "audit",
    107                 doNotPauseOnExceptionsAndMuteConsole: true,
    108             });
    109             let remoteObject = WI.RemoteObject.fromPayload(result, WI.mainTarget);
    110 
    111             if (wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
     115            metadata.startTimestamp = new Date;
     116            let evaluateResponse = await RuntimeAgent.evaluate.invoke(evaluateArguments);
     117            metadata.endTimestamp = new Date;
     118
     119            let remoteObject = WI.RemoteObject.fromPayload(evaluateResponse.result, WI.mainTarget);
     120            if (evaluateResponse.wasThrown || (remoteObject.type === "object" && remoteObject.subtype === "error"))
    112121                addError(remoteObject.description);
    113122            else if (remoteObject.type === "boolean")
     
    222231                addError(WI.UIString("Return value is not an object, string, or boolean"));
    223232        } catch (error) {
     233            metadata.endTimestamp = new Date;
    224234            addError(error.message);
    225235        }
     
    230240        let options = {
    231241            description: this.description,
     242            metadata,
    232243        };
    233244        if (!isEmptyObject(data))
  • trunk/Source/WebInspectorUI/UserInterface/Models/AuditTestCaseResult.js

    r237613 r237644  
    2626WI.AuditTestCaseResult = class AuditTestCaseResult extends WI.AuditTestResultBase
    2727{
    28     constructor(name, level, {data, description} = {})
     28    constructor(name, level, {description, data, metadata} = {})
    2929    {
    3030        console.assert(Object.values(WI.AuditTestCaseResult.Level).includes(level));
    3131        console.assert(!data || typeof data === "object");
     32        console.assert(!metadata || typeof metadata === "object");
    3233
    3334        super(name, {description});
     
    3536        this._level = level;
    3637        this._data = data || {};
     38        this._metadata = metadata || {};
    3739    }
    3840
     
    4446            return null;
    4547
    46         let {type, name, description, level, data} = payload;
     48        let {type, name, description, level, data, metadata} = payload;
    4749
    4850        if (type !== WI.AuditTestCaseResult.TypeIdentifier)
     
    5759        if (typeof data !== "object" || data === null)
    5860            data = {};
     61        else {
     62            function checkArray(key) {
     63                if (!data[key])
     64                    return;
    5965
    60         function checkArray(key) {
    61             if (!data[key])
    62                 return;
     66                if (!Array.isArray(data[key]))
     67                    data[key] = [];
    6368
    64             if (!Array.isArray(data[key]))
    65                 data[key] = [];
     69                data[key] = data[key].filter((item) => typeof item === "string");
     70            }
     71            checkArray("domNodes");
     72            checkArray("domAttributes");
     73            checkArray("errors");
     74        }
    6675
    67             data[key] = data[key].filter((item) => typeof item === "string");
     76        if (typeof metadata !== "object" || metadata === null)
     77            metadata = {};
     78        else {
     79            metadata.startTimestamp = typeof metadata.startTimestamp === "string" ? new Date(metadata.startTimestamp) : null;
     80            metadata.endTimestamp = typeof metadata.endTimestamp === "string" ? new Date(metadata.endTimestamp) : null;
     81            metadata.url = typeof metadata.url === "string" ? metadata.url : null;
    6882        }
    69         checkArray("domNodes");
    70         checkArray("domAttributes");
    71         checkArray("errors");
    7283
    7384        let options = {};
    7485        if (typeof description === "string")
    7586            options.description = description;
    76         if (!isEmptyObject(data))
    77             options.data = data;
     87        if (!isEmptyObject(data)) {
     88            options.data = {};
     89            if (data.domNodes && data.domNodes.length)
     90                options.data.domNodes = data.domNodes;
     91            if (data.domAttributes && data.domAttributes.length)
     92                options.data.domAttributes = data.domAttributes;
     93            if (data.errors && data.errors.length)
     94                options.data.errors = data.errors;
     95        }
     96        if (!isEmptyObject(metadata)) {
     97            options.metadata = {};
     98            if (metadata.startTimestamp && !isNaN(metadata.startTimestamp))
     99                options.metadata.startTimestamp = metadata.startTimestamp;
     100            if (metadata.endTimestamp && !isNaN(metadata.endTimestamp))
     101                options.metadata.endTimestamp = metadata.endTimestamp;
     102            if (metadata.url)
     103                options.metadata.url = metadata.url;
     104        }
    78105        return new WI.AuditTestCaseResult(name, level, options);
    79106    }
     
    83110    get level() { return this._level; }
    84111    get data() { return this._data; }
     112    get metadata() { return this._metadata; }
    85113
    86114    get result()
     
    130158            json.data = data;
    131159
     160        let metadata = {};
     161        if (this._metadata.startTimestamp && !isNaN(this._metadata.startTimestamp))
     162            metadata.startTimestamp = this._metadata.startTimestamp;
     163        if (this._metadata.endTimestamp && !isNaN(this._metadata.endTimestamp))
     164            metadata.endTimestamp = this._metadata.endTimestamp;
     165        if (this._metadata.url)
     166            metadata.url = this._metadata.url;
     167        if (!isEmptyObject(metadata))
     168            json.metadata = metadata;
     169
    132170        return json;
    133171    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.css

    r237613 r237644  
    3838}
    3939
    40 .content-view.audit-test-case > header > h1 {
     40.content-view.audit-test-case > header h1 {
    4141    display: flex;
    4242    align-items: center;
    4343}
    4444
    45 .content-view.audit-test-case > header > h1 > img {
     45.content-view.audit-test-case > header h1 > img {
    4646    width: 1em;
    4747    height: 1em;
     
    4949    min-height: 16px;
    5050    -webkit-margin-end: 4px;
     51}
     52
     53.content-view.audit-test-case > header > .metadata {
     54    display: flex;
     55    align-items: center;
     56    text-align: end;
     57}
     58
     59.content-view.audit-test-case > header > .metadata > .source > time {
     60    display: block;
     61    font-style: italic;
     62    white-space: nowrap;
     63}
     64
     65.content-view.audit-test-case > header > .metadata > .source > a {
     66    display: block;
     67}
     68
     69.content-view.audit-test-case > header > .metadata > .duration {
     70    display: inline-block;
     71    width: var(--metadata-width);
     72    -webkit-margin-start: var(--audit-test-horizontal-space);
     73    font-size: 12px;
     74    font-weight: bold;
    5175}
    5276
  • trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestCaseContentView.js

    r237613 r237644  
    4141        super.initialLayout();
    4242
    43         let nameElement = this.headerView.element.appendChild(document.createElement("h1"));
     43        let informationContainer = this.headerView.element.appendChild(document.createElement("div"));
     44        informationContainer.classList.add("information");
     45
     46        let nameElement = informationContainer.appendChild(document.createElement("h1"));
    4447
    4548        this._resultImageElement = nameElement.appendChild(document.createElement("img"));
     
    4851
    4952        if (this.representedObject.description) {
    50             let descriptionElement = this.headerView.element.appendChild(document.createElement("p"));
     53            let descriptionElement = informationContainer.appendChild(document.createElement("p"));
    5154            descriptionElement.textContent = this.representedObject.description;
    5255        }
     56
     57        this._metadataElement = this.headerView.element.appendChild(document.createElement("div"));
     58        this._metadataElement.classList.add("metadata");
    5359    }
    5460
     
    6167
    6268        this._resultImageElement.src = "Images/AuditTestNoResult.svg";
     69        this._metadataElement.removeChildren();
    6370
    6471        this.contentView.element.removeChildren();
     
    8794            this._resultImageElement.src = "Images/AuditTestUnsupported.svg";
    8895
     96        let metadata = result.metadata;
     97        if (metadata) {
     98            let sourceContainer = this._metadataElement.appendChild(document.createElement("div"));
     99            sourceContainer.classList.add("source");
     100
     101            if (metadata.startTimestamp) {
     102                let timeElement = sourceContainer.appendChild(document.createElement("time"));
     103                timeElement.datetime = metadata.startTimestamp.toISOString();
     104                timeElement.textContent = metadata.startTimestamp.toLocaleString();
     105
     106                if (metadata.endTimestamp) {
     107                    let durationElement = this._metadataElement.appendChild(document.createElement("span"));
     108                    durationElement.classList.add("duration");
     109                    durationElement.textContent = Number.secondsToString((metadata.endTimestamp - metadata.startTimestamp) / 1000);
     110                }
     111            }
     112
     113            if (metadata.url && metadata.url !== WI.networkManager.mainFrame.url) {
     114                let url = new URL(metadata.url);
     115                let origin = url.origin;
     116                if (url.pathname.startsWith("/"))
     117                    origin += "/";
     118                let linkElement = WI.linkifyURLAsNode(url.href, origin + url.href.substring(origin.length).truncateStart(20));
     119                linkElement.title = url.href;
     120                sourceContainer.appendChild(linkElement);
     121            }
     122        }
     123
    89124        let resultData = result.data;
    90125
  • trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestContentView.css

    r237613 r237644  
    5353
    5454.content-view.audit-test > header {
     55    display: flex;
     56    align-items: center;
    5557    padding: var(--audit-test-vertical-space) var(--audit-test-horizontal-space);
     58
     59    --metadata-width: 60px;
     60}
     61
     62.content-view.audit-test > header > .information {
     63    flex-grow: 1;
    5664}
    5765
  • trunk/Source/WebInspectorUI/UserInterface/Views/AuditTestGroupContentView.css

    r237613 r237644  
    2929
    3030.content-view.audit-test-group > header {
    31     display: flex;
    32     align-items: center;
    3331    margin-top: -1px;
    3432    border-top: 1px solid var(--border-color);
     
    6058    padding-right: calc(var(--audit-test-horizontal-space) / 2);
    6159    padding-left: calc(var(--audit-test-horizontal-space) / 2);
    62 }
    63 
    64 .content-view.audit-test-group > header > .information {
    65     flex-grow: 1;
    6660}
    6761
     
    126120
    127121.content-view.audit-test-group > header > .percentage-pass {
     122    width: var(--metadata-width);
    128123    -webkit-margin-start: var(--audit-test-horizontal-space);
    129     width: 60px;
    130124    font-size: 24px;
    131125    text-align: center;
Note: See TracChangeset for help on using the changeset viewer.