/* * Copyright (C) 2018 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ WI.AuditTestCaseResult = class AuditTestCaseResult extends WI.AuditTestResultBase { constructor(name, level, {description, data, metadata, resolvedDOMNodes} = {}) { console.assert(Object.values(WI.AuditTestCaseResult.Level).includes(level)); console.assert(!data || typeof data === "object"); console.assert(!metadata || typeof metadata === "object"); super(name, {description}); this._level = level; this._data = data || {}; this._metadata = metadata || {}; // This array is a mirror of `this._data.domNodes` where each item is a `WI.DOMNode`. this._resolvedDOMNodes = resolvedDOMNodes || []; } // Static static async fromPayload(payload) { if (typeof payload !== "object" || payload === null) return null; if (payload.type !== WI.AuditTestCaseResult.TypeIdentifier) return null; if (typeof payload.name !== "string") { WI.AuditManager.synthesizeError(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("name"))); return null; } if (!Object.values(WI.AuditTestCaseResult.Level).includes(payload.level)) { WI.AuditManager.synthesizeError(WI.UIString("\u0022%s\u0022 has an invalid \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("level"))); return null; } if (typeof payload.data !== "object" || payload.data === null) { if ("data" in payload) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-object \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("data"))); payload.data = {}; } else { function checkArray(key) { if (!(key in payload.data)) return; if (!Array.isArray(payload.data[key])) { WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-array \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("data.%s").format(key))); payload.data[key] = []; } payload.data[key] = payload.data[key].filter((item) => typeof item === "string"); } checkArray("domNodes"); checkArray("domAttributes"); checkArray("errors"); } if (typeof payload.metadata !== "object" || payload.metadata === null) { if ("metadata" in payload) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-object \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("metadata"))); payload.metadata = {}; } else { if (typeof payload.metadata.startTimestamp === "string") payload.metadata.startTimestamp = new Date(payload.metadata.startTimestamp); else { if ("startTimestamp" in payload.metadata) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-object \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("metadata.startTimestamp"))); payload.metadata.startTimestamp = null; } if (typeof payload.metadata.asyncTimestamp === "string") payload.metadata.asyncTimestamp = new Date(payload.metadata.asyncTimestamp); else { if ("asyncTimestamp" in payload.metadata) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-object \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("metadata.asyncTimestamp"))); payload.metadata.asyncTimestamp = null; } if (typeof payload.metadata.endTimestamp === "string") payload.metadata.endTimestamp = new Date(payload.metadata.endTimestamp); else { if ("endTimestamp" in payload.metadata) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-object \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("metadata.endTimestamp"))); payload.metadata.endTimestamp = null; } if (typeof payload.metadata.url !== "string") { if ("url" in payload.metadata) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-object \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("metadata.url"))); payload.metadata.url = null; } } let options = {}; if (typeof payload.description === "string") options.description = payload.description; else if ("description" in payload) WI.AuditManager.synthesizeWarning(WI.UIString("\u0022%s\u0022 has a non-string \u0022%s\u0022 value").format(payload.name, WI.unlocalizedString("description"))); if (!isEmptyObject(payload.data)) { options.data = {}; for (let key in payload.data) { if (key === "domNodes" || key === "domAttributes" || key === "errors") { if (!payload.data[key].length) continue; } if (key === "domNodes") { if (InspectorBackend.hasDomain("DOM") && (!payload.metadata.url || payload.metadata.url === WI.networkManager.mainFrame.url)) { let documentNode = await new Promise((resolve) => WI.domManager.requestDocument(resolve)); options.resolvedDOMNodes = await Promise.all(payload.data.domNodes.map(async (domNodeString) => { let nodeId = 0; try { nodeId = await documentNode.querySelector(domNodeString); } catch { } return WI.domManager.nodeForId(nodeId); })); } } options.data[key] = payload.data[key]; } } if (!isEmptyObject(payload.metadata)) { options.metadata = {}; if (payload.metadata.startTimestamp && !isNaN(payload.metadata.startTimestamp)) options.metadata.startTimestamp = payload.metadata.startTimestamp; if (payload.metadata.asyncTimestamp && !isNaN(payload.metadata.asyncTimestamp)) options.metadata.asyncTimestamp = payload.metadata.asyncTimestamp; if (payload.metadata.endTimestamp && !isNaN(payload.metadata.endTimestamp)) options.metadata.endTimestamp = payload.metadata.endTimestamp; if (payload.metadata.url) options.metadata.url = payload.metadata.url; } return new WI.AuditTestCaseResult(payload.name, payload.level, options); } // Public get level() { return this._level; } get data() { return this._data; } get metadata() { return this._metadata; } get resolvedDOMNodes() { return this._resolvedDOMNodes; } get result() { return this; } get didPass() { return this._level === WI.AuditTestCaseResult.Level.Pass; } get didWarn() { return this._level === WI.AuditTestCaseResult.Level.Warn; } get didFail() { return this._level === WI.AuditTestCaseResult.Level.Fail; } get didError() { return this._level === WI.AuditTestCaseResult.Level.Error; } get unsupported() { return this._level === WI.AuditTestCaseResult.Level.Unsupported; } toJSON() { let json = super.toJSON(); json.level = this._level; let data = {}; for (let key in this._data) { if (key === "domNodes" || key === "domAttributes" || key === "errors") { if (!this._data[key].length) continue; } data[key] = this._data[key]; } if (!isEmptyObject(data)) json.data = data; let metadata = {}; if (this._metadata.startTimestamp && !isNaN(this._metadata.startTimestamp)) metadata.startTimestamp = this._metadata.startTimestamp; if (this._metadata.asyncTimestamp && !isNaN(this._metadata.asyncTimestamp)) metadata.asyncTimestamp = this._metadata.asyncTimestamp; if (this._metadata.endTimestamp && !isNaN(this._metadata.endTimestamp)) metadata.endTimestamp = this._metadata.endTimestamp; if (this._metadata.url) metadata.url = this._metadata.url; if (!isEmptyObject(metadata)) json.metadata = metadata; return json; } }; WI.AuditTestCaseResult.TypeIdentifier = "test-case-result"; // Keep this ordered by precedence. WI.AuditTestCaseResult.Level = { Pass: "pass", Warn: "warn", Fail: "fail", Error: "error", Unsupported: "unsupported", };