--- /dev/null
+const fs = require('fs');
+const jsdom = require('jsdom');
+const path = require('path');
+
+const inPath = process.argv[2];
+const outPath = process.argv[3];
+const settings = process.argv[4] || 'seed=0';
+
+const sleep = ms => new Promise(resolve => { setTimeout(resolve, ms); });
+
+const getElement = (document, selector, index) => {
+ const elements = document.querySelectorAll(selector);
+ if (elements.length - 1 >= index) {
+ return elements[index];
+ }
+ return null;
+};
+
+const waitForElement = async (document, selector, index) => {
+ let element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(100);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(100);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(200);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(200);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(300);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(400);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ await sleep(500);
+ element = getElement(document, selector, index);
+ if (element) {
+ return element;
+ }
+ throw new Error('timeout waiting for element');
+};
+
+(async () => {
+
+const { JSDOM } = jsdom;
+const dom = await JSDOM.fromURL('https://aos.localhorst.tv/surge/?' + settings, {
+ resources: 'usable',
+ runScripts: 'dangerously',
+ storageQuota: 10000000,
+});
+
+const { window } = dom;
+const { document, File, FileList, FileReader } = window;
+
+const blobToBuffer = blob => new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.addEventListener('loadend', e => {
+ if (e.error) {
+ reject(e.error);
+ } else {
+ resolve(Buffer.from(reader.result));
+ }
+ }, false);
+ reader.readAsArrayBuffer(blob);
+});
+
+const fireEvent = (el, eventName) => {
+ eventName = eventName.replace(/on/, '');
+ if (document.createEvent) {
+ var e = document.createEvent('Event');
+ e.initEvent(eventName, true, true);
+ el.dispatchEvent(e);
+ } else if (document.createEventObject) {
+ el.fireEvent('on' + eventName);
+ } else if (typeof el['on' + eventName] === 'function') {
+ el['on' + eventName]();
+ }
+}
+
+const createFile = filePath => {
+ return new File(
+ [new fs.readFileSync(filePath)],
+ path.basename(filePath),
+ );
+}
+
+const addFiles = (input, filePaths) => {
+ if (!Array.isArray(filePaths)) throw new Error('filePaths needs to be a file path string or an Array of file path strings');
+ const fileList = filePaths.map(fp => createFile(fp));
+ fileList.__proto__ = Object.create(FileList.prototype);
+ Object.defineProperty(input, 'files', {
+ value: fileList,
+ writable: false
+ });
+ fireEvent(input, 'change');
+}
+
+Object.defineProperty(window.URL, 'createObjectURL', {
+ value: async blob => {
+ const buffer = await blobToBuffer(blob);
+ fs.writeFile(outPath, buffer, err => {
+ if (err) {
+ throw new Error('failed to write file');
+ }
+ });
+ return 'a';
+ },
+});
+
+const fileInput = await waitForElement(document, 'input[type=file]', 0);
+addFiles(fileInput, [inPath]);
+
+try {
+ await waitForElement(document, 'select', 0);
+ const button = await waitForElement(document, 'button', 1);
+ fireEvent(button, 'click');
+} catch (e) {
+ console.log(dom.serialize());
+ throw e;
+}
+
+})().catch(e => {
+ console.log(e);
+ return 1;
+});