Skip to content

JS (web)

alex [dot] kramer [at] g_m_a_i_l [dot] com edited this page Dec 16, 2022 · 44 revisions

See also: ReactJS, Node.js, TypeScript

Inline blocking sleep()

await new Promise(resolve => setTimeout(resolve, 500)); // sleep for 500 ms

Stale closure value example

let x = 7;
const foo = (val) => {
  return () => { console.log(val); };
}
new_func = foo(x);
new_func(); // => 7
x = 42;
new_func(); // STILL => 7!!!!

Simulate BeforeUnloadEvent (user closing tab/window)

Do this instead of selenium_driver.browser.close so the window doesn't actually close.

let event = document.createEvent('BeforeUnloadEvent');
event.initEvent('beforeunload', true, true);
let userPromptedBeforeLeavingPage = !dispatchEvent(event);

Don't do precise floating point math with 'number'

0.29 - 0.02 === 0.27
> false

Dump entire body html

new XMLSerializer().serializeToString(document);

Jest

Mocking async export default function

import * as ModuleName from "path/moduleName";

let resolver;
const moduleNameSpy = jest.spyOn(
  ModuleName,
  "default"
).mockReturnValue(
  new Promise(
    (resolve, reject) => {
      resolver = resolve;
    }
  )
);

expect(moduleNameSpy).toHaveBeenCalledWith(
  arg1,
  expect.any()
);

await act(
  async () => {
    resolver(someReturnValue);
  }
);

Mocking third-party module

import { v4 } from 'uuid';

jest.mock('uuid', () => ({
  v4: jest.fn()
}));

beforeEach(() => {
  v4.mockReset();
});

describe("Mocking uuid", () => {
  it("mock uuid twice (jk three times)", () => {
    v4
    .mockReturnValueOnce("FIRST TIME")
    .mockReturnValueOnce("SECOND TIME")
    .mockReturnValueOnce("THIRD TIME")

    const result = [v4(), v4()];
    expect(result).toEqual(["FIRST TIME", "SECOND TIME"]);
  });

  it("DO IT AGAIN", () => {
    v4.mockReturnValueOnce("BLURST TIME")
    expect(v4()).toEqual("BLURST TIME");
  })
});

Console recipes

Get specific column from table:

$(`table.SOME_CLASS tr td:nth-child(${INDEX_OF_COLUMN})`).each(function(idx, e) {console.log(e.innerText)})

Delete entire page of reddit comments:

// Uses a basic for loop instead of $.each() in order to delay clicks by awaiting promises 
for (index = 0; index < 25; index++) {
    console.log("Erasing " + index);
    $($("a.edit-usertext")[index]).trigger("click");
    $($(".usertext-edit textarea")[index]).text("🤡");
    $($(".usertext-buttons button.save")[index]).click();
    console.log("Erased " + index);
    await new Promise(resolve => setTimeout(resolve, 800));
    console.log("Deleting " + index);
    $($(".del-button .togglebutton")[0]).trigger("click");
    $($(".del-button .yes")[0]).trigger("click");
    console.log("Deleted " + index);	
    await new Promise(resolve => setTimeout(resolve, 800));
}
location.reload();

Calculate PnL on TDAmeritrade transaction search page:

alert("PnL: " + $("iframe#main").contents().find(".posChange, .negChange").map( function() { return this.innerText.replace(',', ''); } ).toArray().reduce(function(tot, num) { return parseFloat(tot) + parseFloat(num); }))

Download entire NHIS dataset:

// Uses a basic for loop instead of $.each() in order to delay clicks by awaiting timeouts 

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

currentVariableCountString = $($("#dcs .number")[0]).text().trim() || "0";
currentVariableCount = parseInt(currentVariableCountString);

buttons = $(".variablesList .checkbox-column .add_variable:visible");
buttonCount = buttons.size();

targetVariableCount = buttonCount + currentVariableCount;
console.log("\n\n\n=====> CURRENT: " + currentVariableCount + ", NEW: " + buttonCount + ", SUM: " + targetVariableCount);

for (index = 0; index < buttonCount; index++) {
    $(buttons[index]).trigger("click");
    await sleep(200);
}

noUpdateWaitCount = 0;

while (noUpdateWaitCount < 8) {
    newVariableCountString = $($("#dcs .number")[0]).text().trim() || "0";
    newVariableCount = parseInt(newVariableCountString);

    // console.log("====> CURRENT: " + currentVariableCount + ", NEW: " + newVariableCount)

    if (newVariableCount == targetVariableCount) {
        console.log("\n\n=====> 👍👍👍: GREAT SUCCESS! ON TO THE NEXT PAGE...\n\n");
        $("a.next_page")[0].click();
        break;
    }

    if (newVariableCount == currentVariableCount) {
        noUpdateWaitCount++;
    } else {
        currentVariableCount = newVariableCount;
        noUpdateWaitCount = 0;
    }

    await sleep(1000);
}

if (noUpdateWaitCount >= 8) {
    console.log("\n\n=====> 🔥🔥🔥: DIDN'T ADD ALL VARIABLES! TRY AGAIN!\n\n");
    location.reload();
}

Cookie Clicker lolhax

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

stop = false;

while (stop != true) {
    document.getElementById("bigCookie").click();
    await sleep(.0001);
}

Convert hex to blob

tinyWavHex = "52494646c400000057415645666d74201000000001000100401f0000803e00000200100064617461a000000000004f2d14404f2d0000b1d2ecbfb1d200004f2d14404f2d0000b1d2ecbfb1d200004f2d14404f2d0000b1d2ecbfb1d200004f2d14404f2d0000b1d2edbfb1d200004f2d14404f2d0000b1d2edbfb1d200004f2d14404f2d0000b1d2ecbfb1d200004f2d14404f2d0000b1d2edbfb1d200004f2d14404f2d0000b1d2edbfb1d200004f2d14404f2d0000b1d2ecbfb1d200004f2d14404f2d0000b1d2edbfb1d2";

var byteArray = new Uint8Array(tinyWavHex.length/2);

for (var idx = 0; idx < byteArray.length; idx++){
    byteArray[idx] = parseInt(tinyWavHex.substr(idx * 2, 2), 16);
}

var blob = new Blob([byteArray], {type: "audio/wav"});

WebCodecs encode stream

Working example based on https://github.com/w3c/webcodecs/blob/main/explainer.md

<html>
  <head>
    <style>
video {
  border: magenta 2px solid;
}
    </style>
  </head>
  <body>
    <video autoplay id="v">asdf</video>
    <button onclick="clickButtan()">BUTTAN!</button>

    <script>
let mediaStream;

async function main() {
  mediaStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
  const video = document.querySelector("#v");
  video.srcObject = mediaStream;
}

function readAndEncode(reader, encoder) {
  reader.read().then((result) => {
    // App handling for stream closure.
    if (result.done) {
      return;
    }

    // Encode!
    console.log(`ABOUT TO ENCODE. ENCODER STATE IS ${encoder.state}`);
    encoder.encode(result.value);

    // Keep reading until the stream closes.
    readAndEncode(reader, encoder);
  });
}

async function clickButtan() {
  console.log("BUTTAN BUTTEN BUTTUN");

  const audioTrack = mediaStream.getAudioTracks()[0];
  const videoTrack = mediaStream.getVideoTracks()[0];

  const audio = (new MediaStreamTrackProcessor(audioTrack)).readable;
  const video = (new MediaStreamTrackProcessor(videoTrack)).readable;

  const audioEncoder = new AudioEncoder({
    output: (encodedChunk) => {
      console.log(`CHUNK: `, encodedChunk);
    },
    error: (error) => {
      console.log(`ERROR!!!!!!!!!!: `, error);
    },
  });

  const audioTrackSettings = audioTrack.getSettings();
  const sampleRate = audioTrackSettings.sampleRate;
  const sampleSize = audioTrackSettings.sampleSize;
  const channelCount = audioTrackSettings.channelCount;

  try {
    await audioEncoder.configure({
      codec: 'mp3', // https://www.w3.org/TR/webcodecs-codec-registry/
      numberOfChannels: channelCount,
      sampleRate: sampleRate,
      bitrate: sampleRate * sampleSize
    });

    // Finally, feed the encoders data from the track readers
    readAndEncode(audio.getReader(), audioEncoder);
    // readAndEncode(video.getReader(), videoEncoder);
  } catch (exception) {
    // Configuration not supported. More elaborate fallback recommended
    console.log(`CONFIG ERROR!!!!!!!!!!: `, exception);
    return;
  }
}

document.body.onload = main;
    </script>
  </body>
</html>