tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_webconsole_stubs_console_api.js (9068B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const {
      7  STUBS_UPDATE_ENV,
      8  createCommandsForTab,
      9  getStubFile,
     10  getCleanedPacket,
     11  getSerializedPacket,
     12  writeStubsToFile,
     13 } = require(`${CHROME_URL_ROOT}stub-generator-helpers`);
     14 
     15 const TEST_URI =
     16  "https://example.com/browser/devtools/client/webconsole/test/browser/test-console-api.html";
     17 const STUB_FILE = "consoleApi.js";
     18 
     19 add_task(async function () {
     20  const isStubsUpdate = Services.env.get(STUBS_UPDATE_ENV) == "true";
     21  info(`${isStubsUpdate ? "Update" : "Check"} ${STUB_FILE}`);
     22 
     23  const generatedStubs = await generateConsoleApiStubs();
     24 
     25  if (isStubsUpdate) {
     26    await writeStubsToFile(STUB_FILE, generatedStubs);
     27    ok(true, `${STUB_FILE} was updated`);
     28    return;
     29  }
     30  const existingStubs = getStubFile(STUB_FILE);
     31  const FAILURE_MSG =
     32    "The consoleApi stubs file needs to be updated by running `" +
     33    `mach test ${getCurrentTestFilePath()} --headless --setenv WEBCONSOLE_STUBS_UPDATE=true` +
     34    "`";
     35 
     36  if (generatedStubs.size !== existingStubs.rawPackets.size) {
     37    ok(false, FAILURE_MSG);
     38    return;
     39  }
     40 
     41  let failed = false;
     42  for (const [key, packet] of generatedStubs) {
     43    const packetStr = getSerializedPacket(packet, {
     44      sortKeys: true,
     45      replaceActorIds: true,
     46    });
     47    const existingPacketStr = getSerializedPacket(
     48      existingStubs.rawPackets.get(key),
     49      { sortKeys: true, replaceActorIds: true }
     50    );
     51 
     52    is(packetStr, existingPacketStr, `"${key}" packet has expected value`);
     53    failed = failed || packetStr !== existingPacketStr;
     54  }
     55 
     56  if (failed) {
     57    ok(false, FAILURE_MSG);
     58  } else {
     59    ok(true, "Stubs are up to date");
     60  }
     61 });
     62 
     63 async function generateConsoleApiStubs() {
     64  const stubs = new Map();
     65 
     66  const tab = await addTab(TEST_URI);
     67  const commands = await createCommandsForTab(tab);
     68  await commands.targetCommand.startListening();
     69  const resourceCommand = commands.resourceCommand;
     70 
     71  // Ensure waiting for sources in order to populate message.sourceId correctly.
     72  await resourceCommand.watchResources([resourceCommand.TYPES.SOURCE], {
     73    onAvailable() {},
     74  });
     75 
     76  // The resource-watcher only supports a single call to watch/unwatch per
     77  // instance, so we attach a unique watch callback, which will forward the
     78  // resource to `handleConsoleMessage`, dynamically updated for each command.
     79  let handleConsoleMessage = function () {};
     80 
     81  const onConsoleMessage = resources => {
     82    for (const resource of resources) {
     83      handleConsoleMessage(resource);
     84    }
     85  };
     86  await resourceCommand.watchResources(
     87    [resourceCommand.TYPES.CONSOLE_MESSAGE],
     88    {
     89      onAvailable: onConsoleMessage,
     90    }
     91  );
     92 
     93  for (const { keys, code } of getCommands()) {
     94    const received = new Promise(resolve => {
     95      let i = 0;
     96      handleConsoleMessage = async res => {
     97        const callKey = keys[i];
     98 
     99        stubs.set(callKey, getCleanedPacket(callKey, res));
    100 
    101        if (++i === keys.length) {
    102          resolve();
    103        }
    104      };
    105    });
    106 
    107    await SpecialPowers.spawn(
    108      gBrowser.selectedBrowser,
    109      [code],
    110      function (subCode) {
    111        const script = content.document.createElement("script");
    112        script.append(
    113          content.document.createTextNode(
    114            `function triggerPacket() {${subCode}}`
    115          )
    116        );
    117        content.document.body.append(script);
    118        content.wrappedJSObject.triggerPacket();
    119        script.remove();
    120      }
    121    );
    122 
    123    await received;
    124  }
    125 
    126  resourceCommand.unwatchResources([resourceCommand.TYPES.CONSOLE_MESSAGE], {
    127    onAvailable: onConsoleMessage,
    128  });
    129 
    130  await commands.destroy();
    131 
    132  return stubs;
    133 }
    134 
    135 function getCommands() {
    136  const consoleApiCommands = [
    137    "console.log('foobar', 'test')",
    138    "console.log(undefined)",
    139    "console.warn('danger, will robinson!')",
    140    "console.log(NaN)",
    141    "console.log(null)",
    142    "console.log('\u9f2c')",
    143    "console.clear()",
    144    "console.count('bar')",
    145    "console.assert(false, {message: 'foobar'})",
    146    "console.log('\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165')",
    147    "console.dirxml(window)",
    148    "console.log('myarray', ['red', 'green', 'blue'])",
    149    "console.log('myregex', /a.b.c/)",
    150    "console.table(['red', 'green', 'blue']);",
    151    "console.log('myobject', {red: 'redValue', green: 'greenValue', blue: 'blueValue'});",
    152    "console.debug('debug message');",
    153    "console.info('info message');",
    154    "console.error('error message');",
    155    "console.log(Symbol.for('foo'))",
    156    "console.log(Symbol.for('bar'))",
    157  ];
    158 
    159  const consoleApi = consoleApiCommands.map(cmd => ({
    160    keys: [cmd],
    161    code: cmd,
    162  }));
    163 
    164  consoleApi.push(
    165    {
    166      keys: ["console.log('mymap')"],
    167      code: `
    168  var map = new Map();
    169  map.set("key1", "value1");
    170  map.set("key2", "value2");
    171  console.log('mymap', map);
    172  `,
    173    },
    174    {
    175      keys: ["console.log('myset')"],
    176      code: `
    177  console.log('myset', new Set(["a", "b"]));
    178  `,
    179    },
    180    {
    181      keys: ["console.trace()"],
    182      code: `
    183  function testStacktraceFiltering() {
    184    console.trace()
    185  }
    186  function foo() {
    187    testStacktraceFiltering()
    188  }
    189 
    190  foo()
    191  `,
    192    },
    193    {
    194      keys: ["console.trace('bar', {'foo': 'bar'}, [1,2,3])"],
    195      code: `
    196  function testStacktraceWithLog() {
    197    console.trace('bar', {'foo': 'bar'}, [1,2,3])
    198  }
    199  function foo() {
    200    testStacktraceWithLog()
    201  }
    202 
    203  foo()
    204  `,
    205    },
    206    {
    207      keys: ['console.trace("%cHello%c|%cWorld")'],
    208      code: `
    209    console.trace(
    210      "%cHello%c|%cWorld",
    211      "color:red",
    212      "",
    213      "color: blue"
    214    );
    215  `,
    216    },
    217    {
    218      keys: [
    219        "console.time('bar')",
    220        "timerAlreadyExists",
    221        "console.timeLog('bar') - 1",
    222        "console.timeLog('bar') - 2",
    223        "console.timeEnd('bar')",
    224        "timeEnd.timerDoesntExist",
    225        "timeLog.timerDoesntExist",
    226      ],
    227      code: `
    228  console.time("bar");
    229  console.time("bar");
    230  console.timeLog("bar");
    231  console.timeLog("bar", "second call", {state: 1});
    232  console.timeEnd("bar");
    233  console.timeEnd("bar");
    234  console.timeLog("bar");
    235  `,
    236    },
    237    {
    238      keys: ["console.table('bar')"],
    239      code: `
    240  console.table('bar');
    241  `,
    242    },
    243    {
    244      keys: ["console.table(['a', 'b', 'c'])"],
    245      code: `
    246  console.table(['a', 'b', 'c']);
    247  `,
    248    },
    249    {
    250      keys: ["console.group('bar')", "console.groupEnd('bar')"],
    251      code: `
    252  console.group("bar");
    253  console.groupEnd();
    254  `,
    255    },
    256    {
    257      keys: ["console.groupCollapsed('foo')", "console.groupEnd('foo')"],
    258      code: `
    259  console.groupCollapsed("foo");
    260  console.groupEnd();
    261  `,
    262    },
    263    {
    264      keys: ["console.group()", "console.groupEnd()"],
    265      code: `
    266  console.group();
    267  console.groupEnd();
    268  `,
    269    },
    270    {
    271      keys: ["console.log(%cfoobar)"],
    272      code: `
    273  console.log(
    274    "%cfoo%cbar",
    275    "color:blue; font-size:1.3em; background:url('data:image/png,base64,iVBORw0KGgoAAAAN'), url('https://example.com/test'); position:absolute; top:10px; ",
    276    "color:red; line-height: 1.5; background:\\165rl('https://example.com/test')"
    277  );
    278  `,
    279    },
    280    {
    281      keys: ['console.log("%cHello%c|%cWorld")'],
    282      code: `
    283    console.log(
    284      "%cHello%c|%cWorld",
    285      "color:red",
    286      "",
    287      "color: blue"
    288    );
    289  `,
    290    },
    291    {
    292      keys: ["console.group(%cfoo%cbar)", "console.groupEnd(%cfoo%cbar)"],
    293      code: `
    294  console.group(
    295    "%cfoo%cbar",
    296    "color:blue;font-size:1.3em;background:url('https://example.com/test');position:absolute;top:10px",
    297    "color:red;background:\\165rl('https://example.com/test')");
    298  console.groupEnd();
    299  `,
    300    },
    301    {
    302      keys: [
    303        "console.groupCollapsed(%cfoo%cbaz)",
    304        "console.groupEnd(%cfoo%cbaz)",
    305      ],
    306      code: `
    307  console.groupCollapsed(
    308    "%cfoo%cbaz",
    309    "color:blue;font-size:1.3em;background:url('https://example.com/test');position:absolute;top:10px",
    310    "color:red;background:\\165rl('https://example.com/test')");
    311  console.groupEnd();
    312  `,
    313    },
    314    {
    315      keys: ["console.dir({C, M, Y, K})"],
    316      code: "console.dir({cyan: 'C', magenta: 'M', yellow: 'Y', black: 'K'});",
    317    },
    318    {
    319      keys: [
    320        "console.count | default: 1",
    321        "console.count | default: 2",
    322        "console.count | test counter: 1",
    323        "console.count | test counter: 2",
    324        "console.count | default: 3",
    325        "console.count | clear",
    326        "console.count | default: 4",
    327        "console.count | test counter: 3",
    328        "console.countReset | test counter: 0",
    329        "console.countReset | counterDoesntExist",
    330      ],
    331      code: `
    332      console.count();
    333      console.count();
    334      console.count("test counter");
    335      console.count("test counter");
    336      console.count();
    337      console.clear();
    338      console.count();
    339      console.count("test counter");
    340      console.countReset("test counter");
    341      console.countReset("test counter");
    342  `,
    343    },
    344    {
    345      keys: ["console.log escaped characters"],
    346      code: "console.log('hello \\nfrom \\rthe \\\"string world!')",
    347    }
    348  );
    349  return consoleApi;
    350 }