Webview doesn’t finish loading URL

Hi all – Scriptable / JavaScript newbie here.

I’m looking to run this code in an automated fashion through Scriptable. To do that, I’ll have to first log into the website (https://dict.leo.org/trainer/manageFolder.php?lp=ende&lang=de). The issue is that parts of the website, including the login form, are loaded through <script> tags which webView doesn’t seem to evaluate.

My current code looks like this:

const url = ‘https://dict.leo.org/trainer/manageFolder.php?lp=ende&lang=de’;
const user = ‘username’;
const pass = ‘password’;

let wv = new WebView();
await wv.loadURL(url);

// await wv.present();

const js = `
document.querySelector('input[name=login]').value = '${user}';
document.querySelector('input[name=password]').value = '${pass}';
document.querySelector('input[type=submit]').click();
`
await wv.evaluateJavaScript(js);

I can get the code to work if I include

await wv.present();

after

await wv.loadURL(url);

but without that line, I always get the following error:

Error: Failed evaluating JavaScript with error on line 2: TypeError: null is not an object (evaluating ‘document.querySelector(‘input[name=login]’).value = ‘username’’)

Is there any way to achieve the same effect as through WebView.present() but without actually showing the website?

Thanks in advance for your help.

You’ve said that the login form is loaded from a script tag in the website. This is done after the website has loaded and wv.loadURL only waits for the website to finish loading.

This means that there are two ways to solve this:

  1. Wait some time between .loadURL and .evaluateJavaScript. Depending on the time and your internet connection speed it might not work every time (if the latter is slower than the time you wait)
  2. Check inside the evaluated javascript if the element exists. If not, then wait some time and repeat. If yes, enter your information and log in. You should implement a maximum wait time though so that you don’t have to wait forever e.g. if the connection fails.

Thanks for the suggestion. I’ve tried to adjust the code as per below, such that the script checks after 5s whether the login input field is present, but it still only works if I include await wv.present();. Otherwise the code will print to ‘no login required’, even though login is required.

Based on the console.log() statements I’ve included, it seems like the code runs in the correct sequence, i.e. evaluateJavaScript is indeed triggered only after the 5s wait. Any idea what I could be doing wrong?

const url = 'https://dict.leo.org/trainer/manageFolder.php?lp=ende&lang=de';
const user = ‘username’;
const pass = ‘password’;

let wv = new WebView();
await wv.loadURL(url);
console.log(`Loading URL at ${Date.now()}`);

const leoLogin = async function() {
  console.log(`Attempting login at ${Date.now()}`);
  // await wv.present();
  let js = `
  let loginRequired = document.querySelector('input[name=login]');
  if (loginRequired) {
    console.log('login required');
  } else {
    console.log('no login required');
  }
  `
  await wv.evaluateJavaScript(js);
}

// Delay execution of login for 5s until all scripts have been loaded
Timer.schedule(5000,false,leoLogin)

This is quite interesting.

I get the same result as you when I run your snippet and I don’t have an idea how to solve it. I’ll have a look when I’m at home at my PC.