Module: Applitools::Selenium::Scripts

Defined in:
lib/applitools/selenium/scripts/get_element_xpath.rb,
lib/applitools/selenium/scripts/process_page_and_poll.rb,
lib/applitools/selenium/scripts/process_page_and_serialize.rb

Constant Summary collapse

GET_ELEMENT_XPATH_JS =
"        var el = arguments[0];\n        var xpath = '';\n        do {\n          var parent = el.parentElement;\n          var index = 1;\n          if (parent !== null) {\n            var children = parent.children;\n            for (var childIdx in children) {\n              var child = children[childIdx];\n              if (child === el) break;\n              if (child.tagName === el.tagName) index++;\n            }\n          }\n          xpath = '/' + el.tagName + '[' + index + ']' + xpath;\n          el = parent;\n        } while (el !== null);\n        return '/' + xpath;\n"
PROCESS_PAGE_AND_POLL =
"/* @applitools/[email protected] */\n\nfunction __processPageAndSerializePoll() {\n  var processPageAndSerializePoll = (function () {\n  'use strict';\n\n  const EYES_NAME_SPACE = '__EYES__APPLITOOLS__';\n\n  function pullify(script, win = window) {\n    return function() {\n      const scriptName = script.name;\n      if (!win[EYES_NAME_SPACE]) {\n        win[EYES_NAME_SPACE] = {};\n      }\n      if (!win[EYES_NAME_SPACE][scriptName]) {\n        win[EYES_NAME_SPACE][scriptName] = {\n          status: 'WIP',\n          value: null,\n          error: null,\n        };\n        script\n          .apply(null, arguments)\n          .then(r => ((resultObject.status = 'SUCCESS'), (resultObject.value = r)))\n          .catch(e => ((resultObject.status = 'ERROR'), (resultObject.error = e.message)));\n      }\n\n      const resultObject = win[EYES_NAME_SPACE][scriptName];\n      if (resultObject.status === 'SUCCESS') {\n        win[EYES_NAME_SPACE][scriptName] = null;\n      }\n\n      return JSON.stringify(resultObject);\n    };\n  }\n\n  var pollify = pullify;\n\n  // This code was copied and modified from https://github.com/beatgammit/base64-js/blob/bf68aaa277/index.js\n  // License: https://github.com/beatgammit/base64-js/blob/bf68aaa277d9de7007cc0c58279c411bb10670ac/LICENSE\n\n  function arrayBufferToBase64(ab) {\n    const lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');\n\n    const uint8 = new Uint8Array(ab);\n    const len = uint8.length;\n    const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n    const parts = [];\n    const maxChunkLength = 16383; // must be multiple of 3\n\n    let tmp;\n\n    // go through the array every three bytes, we'll deal with trailing stuff later\n    for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n      parts.push(encodeChunk(i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));\n    }\n\n    // pad the end with zeros, but make sure to not forget the extra bytes\n    if (extraBytes === 1) {\n      tmp = uint8[len - 1];\n      parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + '==');\n    } else if (extraBytes === 2) {\n      tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n      parts.push(lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3f] + lookup[(tmp << 2) & 0x3f] + '=');\n    }\n\n    return parts.join('');\n\n    function tripletToBase64(num) {\n      return (\n        lookup[(num >> 18) & 0x3f] +\n        lookup[(num >> 12) & 0x3f] +\n        lookup[(num >> 6) & 0x3f] +\n        lookup[num & 0x3f]\n      );\n    }\n\n    function encodeChunk(start, end) {\n      let tmp;\n      const output = [];\n      for (let i = start; i < end; i += 3) {\n        tmp = ((uint8[i] << 16) & 0xff0000) + ((uint8[i + 1] << 8) & 0xff00) + (uint8[i + 2] & 0xff);\n        output.push(tripletToBase64(tmp));\n      }\n      return output.join('');\n    }\n  }\n\n  var arrayBufferToBase64_1 = arrayBufferToBase64;\n\n  function extractLinks(doc = document) {\n    const srcsetUrls = Array.from(doc.querySelectorAll('img[srcset],source[srcset]'))\n      .map(srcsetEl =>\n        srcsetEl\n          .getAttribute('srcset')\n          .split(', ')\n          .map(str => str.trim().split(/\\s+/)[0]),\n      )\n      .reduce((acc, urls) => acc.concat(urls), []);\n\n    const srcUrls = Array.from(\n      doc.querySelectorAll('img[src],source[src],input[type=\"image\"][src]'),\n    ).map(srcEl => srcEl.getAttribute('src'));\n\n    const imageUrls = Array.from(doc.querySelectorAll('image,use'))\n      .map(hrefEl => hrefEl.getAttribute('href') || hrefEl.getAttribute('xlink:href'))\n      .filter(u => u && u[0] !== '#');\n\n    const objectUrls = Array.from(doc.querySelectorAll('object'))\n      .map(el => el.getAttribute('data'))\n      .filter(Boolean);\n\n    const cssUrls = Array.from(doc.querySelectorAll('link[rel=\"stylesheet\"]')).map(link =>\n      link.getAttribute('href'),\n    );\n\n    const videoPosterUrls = Array.from(doc.querySelectorAll('video[poster]')).map(videoEl =>\n      videoEl.getAttribute('poster'),\n    );\n\n    return Array.from(srcsetUrls)\n      .concat(Array.from(srcUrls))\n      .concat(Array.from(imageUrls))\n      .concat(Array.from(cssUrls))\n      .concat(Array.from(videoPosterUrls))\n      .concat(Array.from(objectUrls));\n  }\n\n  var extractLinks_1 = extractLinks;\n\n  function uuid() {\n    return window.crypto.getRandomValues(new Uint32Array(1))[0];\n  }\n\n  var uuid_1 = uuid;\n\n  function isInlineFrame(frame) {\n    return (\n      !/^https?:.+/.test(frame.src) ||\n      (frame.contentDocument &&\n        frame.contentDocument.location &&\n        frame.contentDocument.location.href === 'about:blank')\n    );\n  }\n\n  var isInlineFrame_1 = isInlineFrame;\n\n  function isAccessibleFrame(frame) {\n    try {\n      const doc = frame.contentDocument;\n      return !!(doc && doc.defaultView && doc.defaultView.frameElement);\n    } catch (err) {\n      // for CORS frames\n    }\n  }\n\n  var isAccessibleFrame_1 = isAccessibleFrame;\n\n  function absolutizeUrl(url, absoluteUrl) {\n    return new URL(url, absoluteUrl).href;\n  }\n\n  var absolutizeUrl_1 = absolutizeUrl;\n\n  const NEED_MAP_INPUT_TYPES = new Set([\n    'date',\n    'datetime-local',\n    'email',\n    'month',\n    'number',\n    'password',\n    'search',\n    'tel',\n    'text',\n    'time',\n    'url',\n    'week',\n  ]);\n\n  function domNodesToCdt(docNode, baseUrl) {\n    const cdt = [{nodeType: Node.DOCUMENT_NODE}];\n    const docRoots = [docNode];\n    const canvasElements = [];\n    const inlineFrames = [];\n\n    cdt[0].childNodeIndexes = childrenFactory(cdt, docNode.childNodes);\n    return {cdt, docRoots, canvasElements, inlineFrames};\n\n    function childrenFactory(cdt, elementNodes) {\n      if (!elementNodes || elementNodes.length === 0) return null;\n\n      const childIndexes = [];\n      Array.prototype.forEach.call(elementNodes, elementNode => {\n        const index = elementNodeFactory(cdt, elementNode);\n        if (index !== null) {\n          childIndexes.push(index);\n        }\n      });\n      return childIndexes;\n    }\n\n    function elementNodeFactory(cdt, elementNode) {\n      let node, manualChildNodeIndexes, dummyUrl;\n      const {nodeType} = elementNode;\n\n      if ([Node.ELEMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE].includes(nodeType)) {\n        if (elementNode.nodeName !== 'SCRIPT') {\n          if (\n            elementNode.nodeName === 'STYLE' &&\n            elementNode.sheet &&\n            elementNode.sheet.cssRules.length\n          ) {\n            cdt.push(getCssRulesNode(elementNode));\n            manualChildNodeIndexes = [cdt.length - 1];\n          }\n\n          if (elementNode.tagName === 'TEXTAREA' && elementNode.value !== elementNode.textContent) {\n            cdt.push(getTextContentNode(elementNode));\n            manualChildNodeIndexes = [cdt.length - 1];\n          }\n\n          node = getBasicNode(elementNode);\n          node.childNodeIndexes =\n            manualChildNodeIndexes ||\n            (elementNode.childNodes.length ? childrenFactory(cdt, elementNode.childNodes) : []);\n\n          if (elementNode.shadowRoot) {\n            node.shadowRootIndex = elementNodeFactory(cdt, elementNode.shadowRoot);\n            docRoots.push(elementNode.shadowRoot);\n          }\n\n          if (elementNode.nodeName === 'CANVAS') {\n            dummyUrl = absolutizeUrl_1(`applitools-canvas-${uuid_1()}.png`, baseUrl);\n            node.attributes.push({name: 'data-applitools-src', value: dummyUrl});\n            canvasElements.push({element: elementNode, url: dummyUrl});\n          }\n\n          if (\n            elementNode.nodeName === 'IFRAME' &&\n            isAccessibleFrame_1(elementNode) &&\n            isInlineFrame_1(elementNode)\n          ) {\n            dummyUrl = absolutizeUrl_1(`?applitools-iframe=${uuid_1()}`, baseUrl);\n            node.attributes.push({name: 'data-applitools-src', value: dummyUrl});\n            inlineFrames.push({element: elementNode, url: dummyUrl});\n          }\n        } else {\n          node = getScriptNode(elementNode);\n        }\n      } else if (nodeType === Node.TEXT_NODE) {\n        node = getTextNode(elementNode);\n      } else if (nodeType === Node.DOCUMENT_TYPE_NODE) {\n        node = getDocNode(elementNode);\n      }\n\n      if (node) {\n        cdt.push(node);\n        return cdt.length - 1;\n      } else {\n        return null;\n      }\n    }\n\n    function nodeAttributes({attributes = {}}) {\n      return Object.keys(attributes).filter(k => attributes[k] && attributes[k].name);\n    }\n\n    function getCssRulesNode(elementNode) {\n      return {\n        nodeType: Node.TEXT_NODE,\n        nodeValue: Array.from(elementNode.sheet.cssRules)\n          .map(rule => rule.cssText)\n          .join(''),\n      };\n    }\n\n    function getTextContentNode(elementNode) {\n      return {\n        nodeType: Node.TEXT_NODE,\n        nodeValue: elementNode.value,\n      };\n    }\n\n    function getBasicNode(elementNode) {\n      const node = {\n        nodeType: elementNode.nodeType,\n        nodeName: elementNode.nodeName,\n        attributes: nodeAttributes(elementNode).map(key => {\n          let value = elementNode.attributes[key].value;\n          const name = elementNode.attributes[key].name;\n          if (/^blob:/.test(value)) {\n            value = value.replace(/^blob:/, '');\n          }\n          return {\n            name,\n            value,\n          };\n        }),\n      };\n\n      if (elementNode.tagName === 'INPUT' && ['checkbox', 'radio'].includes(elementNode.type)) {\n        if (elementNode.attributes.checked && !elementNode.checked) {\n          const idx = node.attributes.findIndex(a => a.name === 'checked');\n          node.attributes.splice(idx, 1);\n        }\n        if (!elementNode.attributes.checked && elementNode.checked) {\n          node.attributes.push({name: 'checked'});\n        }\n      }\n\n      if (\n        elementNode.tagName === 'INPUT' &&\n        NEED_MAP_INPUT_TYPES.has(elementNode.type) &&\n        (elementNode.attributes.value && elementNode.attributes.value.value) !== elementNode.value\n      ) {\n        const nodeAttr = node.attributes.find(a => a.name === 'value');\n        if (nodeAttr) {\n          nodeAttr.value = elementNode.value;\n        } else {\n          node.attributes.push({name: 'value', value: elementNode.value});\n        }\n      }\n\n      if (elementNode.tagName === 'OPTION' && elementNode.parentElement.value === elementNode.value) {\n        const nodeAttr = node.attributes.find(a => a.name === 'selected');\n        if (!nodeAttr) {\n          node.attributes.push({name: 'selected', value: ''});\n        }\n      }\n      return node;\n    }\n\n    function getScriptNode(elementNode) {\n      return {\n        nodeType: Node.ELEMENT_NODE,\n        nodeName: 'SCRIPT',\n        attributes: nodeAttributes(elementNode)\n          .map(key => ({\n            name: elementNode.attributes[key].name,\n            value: elementNode.attributes[key].value,\n          }))\n          .filter(attr => attr.name !== 'src'),\n        childNodeIndexes: [],\n      };\n    }\n\n    function getTextNode(elementNode) {\n      return {\n        nodeType: Node.TEXT_NODE,\n        nodeValue: elementNode.nodeValue,\n      };\n    }\n\n    function getDocNode(elementNode) {\n      return {\n        nodeType: Node.DOCUMENT_TYPE_NODE,\n        nodeName: elementNode.nodeName,\n      };\n    }\n  }\n\n  var domNodesToCdt_1 = domNodesToCdt;\n\n  function uniq(arr) {\n    const result = [];\n    new Set(arr).forEach(v => v && result.push(v));\n    return result;\n  }\n\n  var uniq_1 = uniq;\n\n  function aggregateResourceUrlsAndBlobs(resourceUrlsAndBlobsArr) {\n    return resourceUrlsAndBlobsArr.reduce(\n      ({resourceUrls: allResourceUrls, blobsObj: allBlobsObj}, {resourceUrls, blobsObj}) => ({\n        resourceUrls: uniq_1(allResourceUrls.concat(resourceUrls)),\n        blobsObj: Object.assign(allBlobsObj, blobsObj),\n      }),\n      {resourceUrls: [], blobsObj: {}},\n    );\n  }\n\n  var aggregateResourceUrlsAndBlobs_1 = aggregateResourceUrlsAndBlobs;\n\n  function makeGetResourceUrlsAndBlobs({processResource, aggregateResourceUrlsAndBlobs}) {\n    return function getResourceUrlsAndBlobs({documents, urls, forceCreateStyle = false}) {\n      return Promise.all(\n        urls.map(url => processResource({url, documents, getResourceUrlsAndBlobs, forceCreateStyle})),\n      ).then(resourceUrlsAndBlobsArr => aggregateResourceUrlsAndBlobs(resourceUrlsAndBlobsArr));\n    };\n  }\n\n  var getResourceUrlsAndBlobs = makeGetResourceUrlsAndBlobs;\n\n  function filterInlineUrl(absoluteUrl) {\n    return /^(blob|https?):/.test(absoluteUrl);\n  }\n\n  var filterInlineUrl_1 = filterInlineUrl;\n\n  function toUnAnchoredUri(url) {\n    const m = url && url.match(/(^[^#]*)/);\n    const res = (m && m[1]) || url;\n    return (res && res.replace(/\\?\\s*$/, '')) || url;\n  }\n\n  var toUnAnchoredUri_1 = toUnAnchoredUri;\n\n  var noop = () => {};\n\n  function flat(arr) {\n    return arr.reduce((flatArr, item) => flatArr.concat(item), []);\n  }\n\n  var flat_1 = flat;\n\n  function makeProcessResource({\n    fetchUrl,\n    findStyleSheetByUrl,\n    getCorsFreeStyleSheet,\n    extractResourcesFromStyleSheet,\n    extractResourcesFromSvg,\n    sessionCache,\n    cache = {},\n    log = noop,\n  }) {\n    return function processResource({\n      url,\n      documents,\n      getResourceUrlsAndBlobs,\n      forceCreateStyle = false,\n    }) {\n      if (!cache[url]) {\n        if (sessionCache && sessionCache.getItem(url)) {\n          const resourceUrls = getDependencies(url);\n          log('doProcessResource from sessionStorage', url, 'deps:', resourceUrls.slice(1));\n          cache[url] = Promise.resolve({resourceUrls});\n        } else {\n          const now = Date.now();\n          cache[url] = doProcessResource(url).then(result => {\n            log('doProcessResource', `[${Date.now() - now}ms]`, url);\n            return result;\n          });\n        }\n      }\n      return cache[url];\n\n      function doProcessResource(url) {\n        log('fetching', url);\n        const now = Date.now();\n        return fetchUrl(url)\n          .catch(e => {\n            if (probablyCORS(e)) {\n              return {probablyCORS: true, url};\n            } else {\n              throw e;\n            }\n          })\n          .then(({url, type, value, probablyCORS}) => {\n            if (probablyCORS) {\n              sessionCache && sessionCache.setItem(url, []);\n              return {resourceUrls: [url]};\n            }\n\n            log('fetched', `[${Date.now() - now}ms]`, url);\n\n            const thisBlob = {[url]: {type, value}};\n            let dependentUrls;\n            if (/text\\/css/.test(type)) {\n              let styleSheet = findStyleSheetByUrl(url, documents);\n              if (styleSheet || forceCreateStyle) {\n                const {corsFreeStyleSheet, cleanStyleSheet} = getCorsFreeStyleSheet(\n                  value,\n                  styleSheet,\n                );\n                dependentUrls = extractResourcesFromStyleSheet(corsFreeStyleSheet);\n                cleanStyleSheet();\n              }\n            } else if (/image\\/svg/.test(type)) {\n              try {\n                dependentUrls = extractResourcesFromSvg(value);\n                forceCreateStyle = !!dependentUrls;\n              } catch (e) {\n                console.log('could not parse svg content', e);\n              }\n            }\n\n            if (dependentUrls) {\n              const absoluteDependentUrls = dependentUrls\n                .map(resourceUrl => absolutizeUrl_1(resourceUrl, url.replace(/^blob:/, '')))\n                .map(toUnAnchoredUri_1)\n                .filter(filterInlineUrl_1);\n\n              sessionCache && sessionCache.setItem(url, absoluteDependentUrls);\n\n              return getResourceUrlsAndBlobs({\n                documents,\n                urls: absoluteDependentUrls,\n                forceCreateStyle,\n              }).then(({resourceUrls, blobsObj}) => ({\n                resourceUrls,\n                blobsObj: Object.assign(blobsObj, thisBlob),\n              }));\n            } else {\n              sessionCache && sessionCache.setItem(url, []);\n              return {blobsObj: thisBlob};\n            }\n          })\n          .catch(err => {\n            log('error while fetching', url, err);\n            sessionCache && clearFromSessionStorage();\n            return {};\n          });\n      }\n\n      function probablyCORS(err) {\n        const msg =\n          err.message &&\n          (err.message.includes('Failed to fetch') || err.message.includes('Network request failed'));\n        const name = err.name && err.name.includes('TypeError');\n        return msg && name;\n      }\n\n      function getDependencies(url) {\n        const dependentUrls = sessionCache.getItem(url);\n        return [url].concat(dependentUrls ? uniq_1(flat_1(dependentUrls.map(getDependencies))) : []);\n      }\n\n      function clearFromSessionStorage() {\n        log('clearing from sessionStorage:', url);\n        sessionCache.keys().forEach(key => {\n          const dependentUrls = sessionCache.getItem(key);\n          sessionCache.setItem(key, dependentUrls.filter(dep => dep !== url));\n        });\n        log('cleared from sessionStorage:', url);\n      }\n    };\n  }\n\n  var processResource = makeProcessResource;\n\n  function getUrlFromCssText(cssText) {\n    const re = /url\\((?!['\"]?:)['\"]?([^'\")]*)['\"]?\\)/g;\n    const ret = [];\n    let result;\n    while ((result = re.exec(cssText)) !== null) {\n      ret.push(result[1]);\n    }\n    return ret;\n  }\n\n  var getUrlFromCssText_1 = getUrlFromCssText;\n\n  function makeExtractResourcesFromSvg({parser, decoder, extractResourceUrlsFromStyleTags}) {\n    return function(svgArrayBuffer) {\n      const decooder = decoder || new TextDecoder('utf-8');\n      const svgStr = decooder.decode(svgArrayBuffer);\n      const domparser = parser || new DOMParser();\n      const doc = domparser.parseFromString(svgStr, 'image/svg+xml');\n\n      const srcsetUrls = Array.from(doc.querySelectorAll('img[srcset]'))\n        .map(srcsetEl =>\n          srcsetEl\n            .getAttribute('srcset')\n            .split(', ')\n            .map(str => str.trim().split(/\\s+/)[0]),\n        )\n        .reduce((acc, urls) => acc.concat(urls), []);\n\n      const srcUrls = Array.from(doc.querySelectorAll('img[src]')).map(srcEl =>\n        srcEl.getAttribute('src'),\n      );\n\n      const fromHref = Array.from(doc.querySelectorAll('image,use,link[rel=\"stylesheet\"]')).map(\n        e => e.getAttribute('href') || e.getAttribute('xlink:href'),\n      );\n      const fromObjects = Array.from(doc.getElementsByTagName('object')).map(e =>\n        e.getAttribute('data'),\n      );\n      const fromStyleTags = extractResourceUrlsFromStyleTags(doc, false);\n      const fromStyleAttrs = urlsFromStyleAttrOfDoc(doc);\n\n      return srcsetUrls\n        .concat(srcUrls)\n        .concat(fromHref)\n        .concat(fromObjects)\n        .concat(fromStyleTags)\n        .concat(fromStyleAttrs)\n        .filter(u => u[0] !== '#');\n    };\n  }\n\n  function urlsFromStyleAttrOfDoc(doc) {\n    return flat_1(\n      Array.from(doc.querySelectorAll('*[style]'))\n        .map(e => e.style.cssText)\n        .map(getUrlFromCssText_1)\n        .filter(Boolean),\n    );\n  }\n\n  var makeExtractResourcesFromSvg_1 = makeExtractResourcesFromSvg;\n\n  /* global window */\n\n  function fetchUrl(url, fetch = window.fetch) {\n    // Why return a `new Promise` like this? Because people like Atlassian do horrible things.\n    // They monkey patched window.fetch, and made it so it throws a synchronous exception if the route is not well known.\n    // Returning a new Promise guarantees that `fetchUrl` is the async function that it declares to be.\n    return new Promise((resolve, reject) => {\n      return fetch(url, {cache: 'force-cache', credentials: 'same-origin'})\n        .then(resp =>\n          resp.status === 200\n            ? resp.arrayBuffer().then(buff => ({\n                url,\n                type: resp.headers.get('Content-Type'),\n                value: buff,\n              }))\n            : Promise.reject(`bad status code ${resp.status}`),\n        )\n        .then(resolve)\n        .catch(err => reject(err));\n    });\n  }\n\n  var fetchUrl_1 = fetchUrl;\n\n  function sanitizeAuthUrl(urlStr) {\n    const url = new URL(urlStr);\n    if (url.username && url.password) {\n      return urlStr.replace(`${url.username}:${url.password}@`, '');\n    }\n    return urlStr;\n  }\n\n  var sanitizeAuthUrl_1 = sanitizeAuthUrl;\n\n  function makeFindStyleSheetByUrl({styleSheetCache}) {\n    return function findStyleSheetByUrl(url, documents) {\n      const allStylesheets = flat_1(documents.map(d => Array.from(d.styleSheets)));\n      return (\n        styleSheetCache[url] ||\n        allStylesheets.find(styleSheet => {\n          const styleUrl = styleSheet.href && toUnAnchoredUri_1(styleSheet.href);\n          return styleUrl && sanitizeAuthUrl_1(styleUrl) === url;\n        })\n      );\n    };\n  }\n\n  var findStyleSheetByUrl = makeFindStyleSheetByUrl;\n\n  function makeExtractResourcesFromStyleSheet({styleSheetCache, CSSRule = window.CSSRule}) {\n    return function extractResourcesFromStyleSheet(styleSheet) {\n      const urls = uniq_1(\n        Array.from(styleSheet.cssRules || []).reduce((acc, rule) => {\n          const getRuleUrls = {\n            [CSSRule.IMPORT_RULE]: () => {\n              if (rule.styleSheet) {\n                styleSheetCache[rule.styleSheet.href] = rule.styleSheet;\n                return rule.href;\n              }\n            },\n            [CSSRule.FONT_FACE_RULE]: () => getUrlFromCssText_1(rule.cssText),\n            [CSSRule.SUPPORTS_RULE]: () => extractResourcesFromStyleSheet(rule),\n            [CSSRule.MEDIA_RULE]: () => extractResourcesFromStyleSheet(rule),\n            [CSSRule.STYLE_RULE]: () => {\n              let rv = [];\n              for (let i = 0, ii = rule.style.length; i < ii; i++) {\n                const urls = getUrlFromCssText_1(rule.style.getPropertyValue(rule.style[i]));\n                rv = rv.concat(urls);\n              }\n              return rv;\n            },\n          }[rule.type];\n\n          const urls = (getRuleUrls && getRuleUrls()) || [];\n          return acc.concat(urls);\n        }, []),\n      );\n      return urls.filter(u => u[0] !== '#');\n    };\n  }\n\n  var extractResourcesFromStyleSheet = makeExtractResourcesFromStyleSheet;\n\n  function extractResourceUrlsFromStyleAttrs(cdt) {\n    return cdt.reduce((acc, node) => {\n      if (node.nodeType === 1) {\n        const styleAttr =\n          node.attributes && node.attributes.find(attr => attr.name.toUpperCase() === 'STYLE');\n\n        if (styleAttr) acc = acc.concat(getUrlFromCssText_1(styleAttr.value));\n      }\n      return acc;\n    }, []);\n  }\n\n  var extractResourceUrlsFromStyleAttrs_1 = extractResourceUrlsFromStyleAttrs;\n\n  function makeExtractResourceUrlsFromStyleTags(extractResourcesFromStyleSheet) {\n    return function extractResourceUrlsFromStyleTags(doc, onlyDocStylesheet = true) {\n      return uniq_1(\n        Array.from(doc.querySelectorAll('style')).reduce((resourceUrls, styleEl) => {\n          const styleSheet = onlyDocStylesheet\n            ? Array.from(doc.styleSheets).find(styleSheet => styleSheet.ownerNode === styleEl)\n            : styleEl.sheet;\n          return styleSheet\n            ? resourceUrls.concat(extractResourcesFromStyleSheet(styleSheet))\n            : resourceUrls;\n        }, []),\n      );\n    };\n  }\n\n  var extractResourceUrlsFromStyleTags = makeExtractResourceUrlsFromStyleTags;\n\n  function createTempStylsheet(cssArrayBuffer) {\n    const cssText = new TextDecoder('utf-8').decode(cssArrayBuffer);\n    const head = document.head || document.querySelectorAll('head')[0];\n    const style = document.createElement('style');\n    style.type = 'text/css';\n    style.setAttribute('data-desc', 'Applitools tmp variable created by DOM SNAPSHOT');\n    head.appendChild(style);\n\n    // This is required for IE8 and below.\n    if (style.styleSheet) {\n      style.styleSheet.cssText = cssText;\n    } else {\n      style.appendChild(document.createTextNode(cssText));\n    }\n    return style.sheet;\n  }\n\n  var createTempStyleSheet = createTempStylsheet;\n\n  function getCorsFreeStyleSheet(cssArrayBuffer, styleSheet) {\n    let corsFreeStyleSheet;\n    if (styleSheet) {\n      try {\n        styleSheet.cssRules;\n        corsFreeStyleSheet = styleSheet;\n      } catch (e) {\n        console.log(\n          `[dom-snapshot] could not access cssRules for ${styleSheet.href} ${e}\\ncreating temp style for access.`,\n        );\n        corsFreeStyleSheet = createTempStyleSheet(cssArrayBuffer);\n      }\n    } else {\n      corsFreeStyleSheet = createTempStyleSheet(cssArrayBuffer);\n    }\n\n    return {corsFreeStyleSheet, cleanStyleSheet};\n\n    function cleanStyleSheet() {\n      if (corsFreeStyleSheet !== styleSheet) {\n        corsFreeStyleSheet.ownerNode.parentNode.removeChild(corsFreeStyleSheet.ownerNode);\n      }\n    }\n  }\n\n  var getCorsFreeStyleSheet_1 = getCorsFreeStyleSheet;\n\n  function base64ToArrayBuffer(base64) {\n    var binary_string = window.atob(base64);\n    var len = binary_string.length;\n    var bytes = new Uint8Array(len);\n    for (var i = 0; i < len; i++) {\n      bytes[i] = binary_string.charCodeAt(i);\n    }\n    return bytes.buffer;\n  }\n\n  var base64ToArrayBuffer_1 = base64ToArrayBuffer;\n\n  function buildCanvasBlobs(canvasElements) {\n    return canvasElements.map(({url, element}) => {\n      const data = element.toDataURL('image/png');\n      const value = base64ToArrayBuffer_1(data.split(',')[1]);\n      return {url, type: 'image/png', value};\n    });\n  }\n\n  var buildCanvasBlobs_1 = buildCanvasBlobs;\n\n  function extractFrames(documents = [document]) {\n    const iframes = flat_1(\n      documents.map(d => Array.from(d.querySelectorAll('iframe[src]:not([src=\"\"])'))),\n    );\n\n    return iframes.filter(f => isAccessibleFrame_1(f) && !isInlineFrame_1(f)).map(f => f.contentDocument);\n  }\n\n  var extractFrames_1 = extractFrames;\n\n  const getBaesUrl = function(doc) {\n    const baseUrl = doc.querySelectorAll('base')[0] && doc.querySelectorAll('base')[0].href;\n    if (baseUrl && isUrl(baseUrl)) {\n      return baseUrl;\n    }\n  };\n\n  function isUrl(url) {\n    return url && !/^(about:blank|javascript:void|blob:)/.test(url);\n  }\n\n  var getBaseUrl = getBaesUrl;\n\n  function toUriEncoding(url) {\n    const result =\n      (url &&\n        url.replace(/(\\\\[0-9a-fA-F]{1,6}\\s?)/g, s => {\n          const int = parseInt(s.substr(1).trim(), 16);\n          return String.fromCodePoint(int);\n        })) ||\n      url;\n    return result;\n  }\n\n  var toUriEncoding_1 = toUriEncoding;\n\n  function makeLog(referenceTime) {\n    return function log() {\n      const args = ['[dom-snapshot]', `[+${Date.now() - referenceTime}ms]`].concat(\n        Array.from(arguments),\n      );\n      console.log.apply(console, args);\n    };\n  }\n\n  var log = makeLog;\n\n  const RESOURCE_STORAGE_KEY = '__process_resource';\n\n  function makeSessionCache({log, sessionStorage}) {\n    let sessionStorageCache;\n    try {\n      sessionStorage = sessionStorage || window.sessionStorage;\n      const sessionStorageCacheStr = sessionStorage.getItem(RESOURCE_STORAGE_KEY);\n      sessionStorageCache = sessionStorageCacheStr ? JSON.parse(sessionStorageCacheStr) : {};\n    } catch (ex) {\n      log('error creating session cache', ex);\n    }\n\n    return {\n      getItem,\n      setItem,\n      keys,\n      persist,\n    };\n\n    function getItem(key) {\n      if (sessionStorageCache) {\n        return sessionStorageCache[key];\n      }\n    }\n\n    function setItem(key, value) {\n      if (sessionStorageCache) {\n        log('saving to in-memory sessionStorage, key:', key, 'value:', value);\n        sessionStorageCache[key] = value;\n      }\n    }\n\n    function keys() {\n      if (sessionStorageCache) {\n        return Object.keys(sessionStorageCache);\n      } else {\n        return [];\n      }\n    }\n\n    function persist() {\n      if (sessionStorageCache) {\n        sessionStorage.setItem(RESOURCE_STORAGE_KEY, JSON.stringify(sessionStorageCache));\n      }\n    }\n  }\n\n  var sessionCache = makeSessionCache;\n\n  function processPage(doc = document, {showLogs, useSessionCache, dontFetchResources} = {}) {\n    const log$$1 = showLogs ? log(Date.now()) : noop;\n    log$$1('processPage start');\n    const sessionCache$$1 = useSessionCache && sessionCache({log: log$$1});\n    const styleSheetCache = {};\n    const extractResourcesFromStyleSheet$$1 = extractResourcesFromStyleSheet({styleSheetCache});\n    const findStyleSheetByUrl$$1 = findStyleSheetByUrl({styleSheetCache});\n    const extractResourceUrlsFromStyleTags$$1 = extractResourceUrlsFromStyleTags(\n      extractResourcesFromStyleSheet$$1,\n    );\n\n    const extractResourcesFromSvg = makeExtractResourcesFromSvg_1({extractResourceUrlsFromStyleTags: extractResourceUrlsFromStyleTags$$1});\n    const processResource$$1 = processResource({\n      fetchUrl: fetchUrl_1,\n      findStyleSheetByUrl: findStyleSheetByUrl$$1,\n      getCorsFreeStyleSheet: getCorsFreeStyleSheet_1,\n      extractResourcesFromStyleSheet: extractResourcesFromStyleSheet$$1,\n      extractResourcesFromSvg,\n      absolutizeUrl: absolutizeUrl_1,\n      log: log$$1,\n      sessionCache: sessionCache$$1,\n    });\n\n    const getResourceUrlsAndBlobs$$1 = getResourceUrlsAndBlobs({\n      processResource: processResource$$1,\n      aggregateResourceUrlsAndBlobs: aggregateResourceUrlsAndBlobs_1,\n    });\n\n    return doProcessPage(doc).then(result => {\n      log$$1('processPage end');\n      return result;\n    });\n\n    function doProcessPage(doc, pageUrl = doc.location.href) {\n      const baseUrl = getBaseUrl(doc) || pageUrl;\n      const {cdt, docRoots, canvasElements, inlineFrames} = domNodesToCdt_1(doc, baseUrl);\n\n      const linkUrls = flat_1(docRoots.map(extractLinks_1));\n      const styleTagUrls = flat_1(docRoots.map(extractResourceUrlsFromStyleTags$$1));\n      const absolutizeThisUrl = getAbsolutizeByUrl(baseUrl);\n      const urls = uniq_1(\n        Array.from(linkUrls)\n          .concat(Array.from(styleTagUrls))\n          .concat(extractResourceUrlsFromStyleAttrs_1(cdt)),\n      )\n        .map(toUriEncoding_1)\n        .map(absolutizeThisUrl)\n        .map(toUnAnchoredUri_1)\n        .filter(filterInlineUrlsIfExisting);\n\n      const resourceUrlsAndBlobsPromise = dontFetchResources\n        ? Promise.resolve({resourceUrls: urls, blobsObj: {}})\n        : getResourceUrlsAndBlobs$$1({documents: docRoots, urls}).then(result => {\n            sessionCache$$1 && sessionCache$$1.persist();\n            return result;\n          });\n      const canvasBlobs = buildCanvasBlobs_1(canvasElements);\n      const frameDocs = extractFrames_1(docRoots);\n\n      const processFramesPromise = frameDocs.map(f =>\n        doProcessPage(f, f.defaultView.frameElement.src),\n      );\n      const processInlineFramesPromise = inlineFrames.map(({element, url}) =>\n        doProcessPage(element.contentDocument, url),\n      );\n\n      const srcAttr =\n        doc.defaultView &&\n        doc.defaultView.frameElement &&\n        doc.defaultView.frameElement.getAttribute('src');\n\n      return Promise.all(\n        [resourceUrlsAndBlobsPromise].concat(processFramesPromise).concat(processInlineFramesPromise),\n      ).then(function(resultsWithFrameResults) {\n        const {resourceUrls, blobsObj} = resultsWithFrameResults[0];\n        const framesResults = resultsWithFrameResults.slice(1);\n        return {\n          cdt,\n          url: pageUrl,\n          srcAttr,\n          resourceUrls: resourceUrls.map(url => url.replace(/^blob:/, '')),\n          blobs: blobsObjToArray(blobsObj).concat(canvasBlobs),\n          frames: framesResults,\n        };\n      });\n    }\n  }\n\n  function getAbsolutizeByUrl(url) {\n    return function(someUrl) {\n      try {\n        return absolutizeUrl_1(someUrl, url);\n      } catch (err) {\n        // can't do anything with a non-absolute url\n      }\n    };\n  }\n\n  function blobsObjToArray(blobsObj) {\n    return Object.keys(blobsObj).map(blobUrl =>\n      Object.assign(\n        {\n          url: blobUrl.replace(/^blob:/, ''),\n        },\n        blobsObj[blobUrl],\n      ),\n    );\n  }\n\n  function filterInlineUrlsIfExisting(absoluteUrl) {\n    return absoluteUrl && filterInlineUrl_1(absoluteUrl);\n  }\n\n  var processPage_1 = processPage;\n\n  function processPageAndSerialize() {\n    return processPage_1.apply(this, arguments).then(serializeFrame);\n  }\n\n  function serializeFrame(frame) {\n    frame.blobs = frame.blobs.map(({url, type, value}) => ({\n      url,\n      type,\n      value: arrayBufferToBase64_1(value),\n    }));\n    frame.frames.forEach(serializeFrame);\n    return frame;\n  }\n\n  var processPageAndSerialize_1 = processPageAndSerialize;\n\n  var processPageAndSerializePoll = pollify(processPageAndSerialize_1);\n\n  return processPageAndSerializePoll;\n\n}());\n\n  return processPageAndSerializePoll.apply(this, arguments);\n}\n"
PROCESS_RESOURCES =
"// @applitools/[email protected]\nfunction __processPageAndSerialize() {\n  var processPageAndSerialize = (function () {\n  'use strict';\n\n  // This code was copied and modified from https://github.com/beatgammit/base64-js/blob/bf68aaa277/index.js\n  // License: https://github.com/beatgammit/base64-js/blob/bf68aaa277d9de7007cc0c58279c411bb10670ac/LICENSE\n\n  function arrayBufferToBase64(ab) {\n    const lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');\n\n    const uint8 = new Uint8Array(ab);\n    const len = uint8.length;\n    const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes\n    const parts = [];\n    const maxChunkLength = 16383; // must be multiple of 3\n\n    let tmp;\n\n    // go through the array every three bytes, we'll deal with trailing stuff later\n    for (let i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n      parts.push(encodeChunk(i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));\n    }\n\n    // pad the end with zeros, but make sure to not forget the extra bytes\n    if (extraBytes === 1) {\n      tmp = uint8[len - 1];\n      parts.push(lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3f] + '==');\n    } else if (extraBytes === 2) {\n      tmp = (uint8[len - 2] << 8) + uint8[len - 1];\n      parts.push(lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3f] + lookup[(tmp << 2) & 0x3f] + '=');\n    }\n\n    return parts.join('');\n\n    function tripletToBase64(num) {\n      return (\n        lookup[(num >> 18) & 0x3f] +\n        lookup[(num >> 12) & 0x3f] +\n        lookup[(num >> 6) & 0x3f] +\n        lookup[num & 0x3f]\n      );\n    }\n\n    function encodeChunk(start, end) {\n      let tmp;\n      const output = [];\n      for (let i = start; i < end; i += 3) {\n        tmp = ((uint8[i] << 16) & 0xff0000) + ((uint8[i + 1] << 8) & 0xff00) + (uint8[i + 2] & 0xff);\n        output.push(tripletToBase64(tmp));\n      }\n      return output.join('');\n    }\n  }\n\n  var arrayBufferToBase64_1 = arrayBufferToBase64;\n\n  function extractLinks(doc = document) {\n    const srcsetUrls = [...doc.querySelectorAll('img[srcset],source[srcset]')]\n      .map(srcsetEl =>\n        srcsetEl\n          .getAttribute('srcset')\n          .split(',')\n          .map(str => str.trim().split(/\\s+/)[0]),\n      )\n      .reduce((acc, urls) => acc.concat(urls), []);\n\n    const srcUrls = [...doc.querySelectorAll('img[src],source[src]')].map(srcEl =>\n      srcEl.getAttribute('src'),\n    );\n\n    const cssUrls = [...doc.querySelectorAll('link[rel=\"stylesheet\"]')].map(link =>\n      link.getAttribute('href'),\n    );\n\n    const videoPosterUrls = [...doc.querySelectorAll('video[poster]')].map(videoEl =>\n      videoEl.getAttribute('poster'),\n    );\n\n    return [...srcsetUrls, ...srcUrls, ...cssUrls, ...videoPosterUrls];\n  }\n\n  var extractLinks_1 = extractLinks;\n\n  /* eslint-disable no-use-before-define */\n\n  function domNodesToCdt(docNode) {\n    const NODE_TYPES = {\n      ELEMENT: 1,\n      TEXT: 3,\n      DOCUMENT: 9,\n      DOCUMENT_TYPE: 10,\n      DOCUMENT_FRAGMENT_NODE: 11,\n    };\n\n    const domNodes = [\n      {\n        nodeType: NODE_TYPES.DOCUMENT,\n      },\n    ];\n    domNodes[0].childNodeIndexes = childrenFactory(domNodes, docNode.childNodes);\n    return domNodes;\n\n    function childrenFactory(domNodes, elementNodes) {\n      if (!elementNodes || elementNodes.length === 0) return null;\n\n      const childIndexes = [];\n      elementNodes.forEach(elementNode => {\n        const index = elementNodeFactory(domNodes, elementNode);\n        if (index !== null) {\n          childIndexes.push(index);\n        }\n      });\n\n      return childIndexes;\n    }\n\n    function elementNodeFactory(domNodes, elementNode) {\n      let node;\n      const {nodeType} = elementNode;\n      if ([NODE_TYPES.ELEMENT, NODE_TYPES.DOCUMENT_FRAGMENT_NODE].includes(nodeType)) {\n        if (elementNode.nodeName !== 'SCRIPT') {\n          if (\n            elementNode.nodeName === 'STYLE' &&\n            !elementNode.textContent &&\n            elementNode.sheet &&\n            elementNode.sheet.cssRules.length\n          ) {\n            elementNode.appendChild(\n              docNode.createTextNode(\n                [...elementNode.sheet.cssRules].map(rule => rule.cssText).join(''),\n              ),\n            );\n          }\n\n          node = {\n            nodeType: nodeType,\n            nodeName: elementNode.nodeName,\n            attributes: Object.keys(elementNode.attributes || {}).map(key => {\n              let value = elementNode.attributes[key].value;\n              const name = elementNode.attributes[key].localName;\n\n              if (/^blob:/.test(value)) {\n                value = value.replace(/^blob:/, '');\n              }\n\n              return {\n                name,\n                value,\n              };\n            }),\n            childNodeIndexes: elementNode.childNodes.length\n              ? childrenFactory(domNodes, elementNode.childNodes)\n              : [],\n          };\n\n          if (elementNode.shadowRoot) {\n            node.shadowRootIndex = elementNodeFactory(domNodes, elementNode.shadowRoot);\n          }\n\n          if (elementNode.checked && !elementNode.attributes.checked) {\n            node.attributes.push({name: 'checked', value: 'checked'});\n          }\n          if (\n            elementNode.value !== undefined &&\n            elementNode.attributes.value === undefined &&\n            elementNode.tagName === 'INPUT'\n          ) {\n            node.attributes.push({name: 'value', value: elementNode.value});\n          }\n        }\n      } else if (nodeType === NODE_TYPES.TEXT) {\n        node = {\n          nodeType: NODE_TYPES.TEXT,\n          nodeValue: elementNode.nodeValue,\n        };\n      } else if (nodeType === NODE_TYPES.DOCUMENT_TYPE) {\n        node = {\n          nodeType: NODE_TYPES.DOCUMENT_TYPE,\n          nodeName: elementNode.nodeName,\n        };\n      }\n\n      if (node) {\n        domNodes.push(node);\n        return domNodes.length - 1;\n      } else {\n        // console.log(`Unknown nodeType: ${nodeType}`);\n        return null;\n      }\n    }\n  }\n\n  var domNodesToCdt_1 = domNodesToCdt;\n  var NODE_TYPES = {\n    ELEMENT: 1,\n    TEXT: 3,\n    DOCUMENT: 9,\n    DOCUMENT_TYPE: 10,\n  };\n  domNodesToCdt_1.NODE_TYPES = NODE_TYPES;\n\n  function extractFrames(doc = document) {\n    return [...doc.querySelectorAll('iframe[src]:not([src=\"\"])')]\n      .map(srcEl => {\n        try {\n          const contentDoc = srcEl.contentDocument;\n          return (\n            contentDoc &&\n            /^https?:$/.test(contentDoc.location.protocol) &&\n            contentDoc.defaultView &&\n            contentDoc.defaultView.frameElement &&\n            contentDoc\n          );\n        } catch (err) {\n          //for CORS frames\n        }\n      })\n      .filter(x => !!x);\n  }\n\n  var extractFrames_1 = extractFrames;\n\n  function uniq(arr) {\n    const result = [];\n    new Set(arr).forEach(v => v && result.push(v));\n    return result;\n  }\n\n  var uniq_1 = uniq;\n\n  function aggregateResourceUrlsAndBlobs(resourceUrlsAndBlobsArr) {\n    return resourceUrlsAndBlobsArr.reduce(\n      ({resourceUrls: allResourceUrls, blobsObj: allBlobsObj}, {resourceUrls, blobsObj}) => ({\n        resourceUrls: uniq_1(allResourceUrls.concat(resourceUrls)),\n        blobsObj: Object.assign(allBlobsObj, blobsObj),\n      }),\n      {resourceUrls: [], blobsObj: {}},\n    );\n  }\n\n  var aggregateResourceUrlsAndBlobs_1 = aggregateResourceUrlsAndBlobs;\n\n  function makeGetResourceUrlsAndBlobs({processResource, aggregateResourceUrlsAndBlobs}) {\n    return function getResourceUrlsAndBlobs(doc, baseUrl, urls) {\n      return Promise.all(\n        urls.map(url => processResource(url, doc, baseUrl, getResourceUrlsAndBlobs.bind(null, doc))),\n      ).then(resourceUrlsAndBlobsArr => aggregateResourceUrlsAndBlobs(resourceUrlsAndBlobsArr));\n    };\n  }\n\n  var getResourceUrlsAndBlobs = makeGetResourceUrlsAndBlobs;\n\n  function filterInlineUrl(absoluteUrl) {\n    return /^(blob|https?):/.test(absoluteUrl);\n  }\n\n  var filterInlineUrl_1 = filterInlineUrl;\n\n  function absolutizeUrl(url, absoluteUrl) {\n    return new URL(url, absoluteUrl).href;\n  }\n\n  var absolutizeUrl_1 = absolutizeUrl;\n\n  function makeProcessResource({\n    fetchUrl,\n    findStyleSheetByUrl,\n    extractResourcesFromStyleSheet,\n    isSameOrigin,\n    cache = {},\n  }) {\n    return function processResource(absoluteUrl, doc, baseUrl, getResourceUrlsAndBlobs) {\n      return cache[absoluteUrl] || (cache[absoluteUrl] = doProcessResource(absoluteUrl));\n\n      function doProcessResource(url) {\n        return fetchUrl(url)\n          .catch(e => {\n            if (probablyCORS(e, url)) {\n              return {probablyCORS: true, url};\n            } else {\n              throw e;\n            }\n          })\n          .then(({url, type, value, probablyCORS}) => {\n            if (probablyCORS) {\n              return {resourceUrls: [url]};\n            }\n            const result = {blobsObj: {[url]: {type, value}}};\n            if (/text\\/css/.test(type)) {\n              const styleSheet = findStyleSheetByUrl(url, doc);\n              if (!styleSheet) {\n                return result;\n              }\n              const resourceUrls = extractResourcesFromStyleSheet(styleSheet, doc.defaultView)\n                .map(resourceUrl => absolutizeUrl_1(resourceUrl, url.replace(/^blob:/, '')))\n                .filter(filterInlineUrl_1);\n              return getResourceUrlsAndBlobs(baseUrl, resourceUrls).then(\n                ({resourceUrls, blobsObj}) => ({\n                  resourceUrls,\n                  blobsObj: Object.assign(blobsObj, {[url]: {type, value}}),\n                }),\n              );\n            } else {\n              return result;\n            }\n          })\n          .catch(err => {\n            console.log('[dom-snapshot] error while fetching', url, err);\n            return {};\n          });\n      }\n\n      function probablyCORS(err, url) {\n        const msgCORS = err.message && err.message.includes('Failed to fetch');\n        const nameCORS = err.name && err.name.includes('TypeError');\n        return msgCORS && nameCORS && !isSameOrigin(url, baseUrl);\n      }\n    };\n  }\n\n  var processResource = makeProcessResource;\n\n  /* global window */\n\n  function fetchUrl(url, fetch = window.fetch) {\n    return fetch(url, {cache: 'force-cache', credentials: 'same-origin'}).then(resp =>\n      resp.arrayBuffer().then(buff => ({\n        url,\n        type: resp.headers.get('Content-Type'),\n        value: buff,\n      })),\n    );\n  }\n\n  var fetchUrl_1 = fetchUrl;\n\n  function makeFindStyleSheetByUrl({styleSheetCache}) {\n    return function findStyleSheetByUrl(url, doc) {\n      return styleSheetCache[url] || [...doc.styleSheets].find(styleSheet => styleSheet.href === url);\n    };\n  }\n\n  var findStyleSheetByUrl = makeFindStyleSheetByUrl;\n\n  function getUrlFromCssText(cssText) {\n    const re = /url\\((?!['\"]?:)['\"]?([^'\")]*)['\"]?\\)/g;\n    const ret = [];\n    let result;\n    while ((result = re.exec(cssText)) !== null) {\n      ret.push(result[1]);\n    }\n    return ret;\n  }\n\n  var getUrlFromCssText_1 = getUrlFromCssText;\n\n  // NOTE this code is very similar to the node part of visual-grid-client, but there is a different related to the browser's cssom with import rules\n  function makeExtractResourcesFromStyleSheet({styleSheetCache}) {\n    return function extractResourcesFromStyleSheet(styleSheet, win = window) {\n      return uniq_1(\n        [...(styleSheet.cssRules || [])].reduce((acc, rule) => {\n          if (rule instanceof win.CSSImportRule) {\n            styleSheetCache[rule.styleSheet.href] = rule.styleSheet;\n            return acc.concat(rule.href);\n          } else if (rule instanceof win.CSSFontFaceRule) {\n            return acc.concat(getUrlFromCssText_1(rule.style.getPropertyValue('src')));\n          } else if (rule instanceof win.CSSSupportsRule || rule instanceof win.CSSMediaRule) {\n            return acc.concat(extractResourcesFromStyleSheet(rule));\n          } else if (rule instanceof win.CSSStyleRule) {\n            for (let i = 0, ii = rule.style.length; i < ii; i++) {\n              const urls = getUrlFromCssText_1(rule.style.getPropertyValue(rule.style[i]));\n              urls.length && (acc = acc.concat(urls));\n            }\n          }\n          return acc;\n        }, []),\n      );\n    };\n  }\n\n  var extractResourcesFromStyleSheet = makeExtractResourcesFromStyleSheet;\n\n  function extractResourceUrlsFromStyleAttrs(cdt) {\n    return cdt.reduce((acc, node) => {\n      if (node.nodeType === 1) {\n        const styleAttr =\n          node.attributes && node.attributes.find(attr => attr.name.toUpperCase() === 'STYLE');\n\n        if (styleAttr) acc = acc.concat(getUrlFromCssText_1(styleAttr.value));\n      }\n      return acc;\n    }, []);\n  }\n\n  var extractResourceUrlsFromStyleAttrs_1 = extractResourceUrlsFromStyleAttrs;\n\n  function makeExtractResourceUrlsFromStyleTags(extractResourcesFromStyleSheet) {\n    return function extractResourceUrlsFromStyleTags(doc) {\n      return uniq_1(\n        [...doc.getElementsByTagName('style')].reduce((resourceUrls, styleEl) => {\n          const styleSheet = [...doc.styleSheets].find(\n            styleSheet => styleSheet.ownerNode === styleEl,\n          );\n          return resourceUrls.concat(extractResourcesFromStyleSheet(styleSheet, doc.defaultView));\n        }, []),\n      );\n    };\n  }\n\n  var extractResourceUrlsFromStyleTags = makeExtractResourceUrlsFromStyleTags;\n\n  function isSameOrigin(url, baseUrl) {\n    const blobOrData = /^(blob|data):/;\n    if (blobOrData.test(url)) return true;\n    if (blobOrData.test(baseUrl)) return false;\n\n    const {origin} = new URL(url, baseUrl);\n    const {origin: baseOrigin} = new URL(baseUrl);\n    return origin === baseOrigin;\n  }\n\n  var isSameOrigin_1 = isSameOrigin;\n\n  function processPage(doc = document) {\n    const styleSheetCache = {};\n    const extractResourcesFromStyleSheet$$1 = extractResourcesFromStyleSheet({styleSheetCache});\n    const findStyleSheetByUrl$$1 = findStyleSheetByUrl({styleSheetCache});\n    const processResource$$1 = processResource({\n      fetchUrl: fetchUrl_1,\n      findStyleSheetByUrl: findStyleSheetByUrl$$1,\n      extractResourcesFromStyleSheet: extractResourcesFromStyleSheet$$1,\n      absolutizeUrl: absolutizeUrl_1,\n      isSameOrigin: isSameOrigin_1,\n    });\n\n    const getResourceUrlsAndBlobs$$1 = getResourceUrlsAndBlobs({\n      processResource: processResource$$1,\n      aggregateResourceUrlsAndBlobs: aggregateResourceUrlsAndBlobs_1,\n    });\n\n    const extractResourceUrlsFromStyleTags$$1 = extractResourceUrlsFromStyleTags(\n      extractResourcesFromStyleSheet$$1,\n    );\n\n    return doProcessPage(doc);\n\n    function doProcessPage(doc) {\n      const frameElement = doc.defaultView && doc.defaultView.frameElement;\n      const url = frameElement ? frameElement.src : doc.location.href;\n\n      const cdt = domNodesToCdt_1(doc);\n\n      const links = uniq_1(\n        extractLinks_1(doc)\n          .concat(extractResourceUrlsFromStyleAttrs_1(cdt))\n          .concat(extractResourceUrlsFromStyleTags$$1(doc)),\n      )\n        .map(absolutizeThisUrl)\n        .filter(filterInlineUrlsIfExisting);\n\n      const resourceUrlsAndBlobsPromise = getResourceUrlsAndBlobs$$1(doc, url, links);\n\n      const frameDocs = extractFrames_1(doc);\n      const processFramesPromise = frameDocs.map(doProcessPage);\n\n      return Promise.all([resourceUrlsAndBlobsPromise, ...processFramesPromise]).then(\n        ([{resourceUrls, blobsObj}, ...framesResults]) => ({\n          cdt,\n          url,\n          resourceUrls,\n          blobs: blobsObjToArray(blobsObj),\n          frames: framesResults,\n          srcAttr: frameElement ? frameElement.getAttribute('src') : undefined,\n        }),\n      );\n\n      function absolutizeThisUrl(someUrl) {\n        try {\n          return absolutizeUrl_1(someUrl, url);\n        } catch (err) {\n          // can't do anything with a non-absolute url\n        }\n      }\n    }\n  }\n\n  function blobsObjToArray(blobsObj) {\n    return Object.keys(blobsObj).map(blobUrl =>\n      Object.assign(\n        {\n          url: blobUrl.replace(/^blob:/, ''),\n        },\n        blobsObj[blobUrl],\n      ),\n    );\n  }\n\n  function filterInlineUrlsIfExisting(absoluteUrl) {\n    return absoluteUrl && filterInlineUrl_1(absoluteUrl);\n  }\n\n  var processPage_1 = processPage;\n\n  function processPageAndSerialize(doc) {\n    return processPage_1(doc).then(serializeFrame);\n  }\n\n  function serializeFrame(frame) {\n    frame.blobs = frame.blobs.map(({url, type, value}) => ({\n      url,\n      type,\n      value: arrayBufferToBase64_1(value),\n    }));\n    frame.frames.forEach(serializeFrame);\n    return frame;\n  }\n\n  var processPageAndSerialize_1 = processPageAndSerialize;\n\n  return processPageAndSerialize_1;\n\n}());\n\n  return processPageAndSerialize.apply(this, arguments);\n}\n"