const run_in_fenced_frame = (func_name, description, is_nested) => {
  promise_test(async test => {
    const key = token();
    const url = is_nested ?
                'resources/sandboxed-features-looser-restriction.sub.html?' :
                'resources/sandboxed-features-inner.sub.html?';
    let params = new URLSearchParams();
    params.set('key', key);
    params.set('test_func', func_name);
    const frame = document.createElement('fencedframe');
    const frame_url = 'resources/sandboxed-features-inner.sub.html?' +
    params.toString();
    const config = new FencedFrameConfig(generateURL(frame_url, []));
    frame.config = config;
    test.add_cleanup(() => {
      frame.remove();
    });
    document.body.appendChild(frame);
    // The test_pointer_lock() function expects the frame to be user activated.
    // This is done at this point because headless mode WPTs do not support
    // testdriver functions from within fenced frames.
    if (func_name == "test_pointer_lock") {
      await multiClick(10, 10, document.body);
    }
    assert_equals(await nextValueFromServer(key), 'done');
  }, description);
};

const run_sanboxed_feature_test = (func_name, description) => {
  run_in_fenced_frame(func_name, description, false);
  run_in_fenced_frame(func_name, description + '[looser sandboxed]', true);
};

async function test_prompt() {
  assert_equals(
    window.prompt('Test prompt'),
    null,
    'window.prompt() must synchronously return null in a fenced frame without' +
    ' blocking on user input.');
}

async function test_alert() {
  assert_equals(
    window.alert('Test alert'),
    undefined,
    'window.alert() must synchronously return undefined in a fenced frame' +
    '  without blocking on user input.');
}

async function test_confirm() {
  assert_equals(
    window.confirm('Test confirm'),
    false,
    'window.confirm() must synchronously return false in a fenced frame' +
    ' without blocking on user input.');
}

async function test_print() {
  assert_equals(
    window.print(),
    undefined,
    'window.print() must synchronously return undefined in a fenced frame' +
    ' without blocking on user input.');

  assert_equals(
    document.execCommand('print', false, null),
    false,
    'execCommand(\'print\') must synchronously return false in a fenced frame' +
    ' without blocking on user input.');
}

async function test_document_domain() {
  assert_throws_dom('SecurityError', () => {
    document.domain = 'example.test';
  });
  assert_throws_dom('SecurityError', () => {
    document.domain = document.domain;
  });
  assert_throws_dom('SecurityError', () => {
    (new Document).domain = document.domain;
  });
  assert_throws_dom('SecurityError', () => {
    document.implementation.createHTMLDocument().domain = document.domain;
  });
  assert_throws_dom('SecurityError', () => {
    document.implementation.createDocument(null, '').domain = document.domain;
  });
  assert_throws_dom('SecurityError', () => {
    document.createElement('template').content.ownerDocument.domain =
        document.domain;
  });
}

async function test_presentation_request() {
  assert_throws_dom('SecurityError', () => {
    new PresentationRequest([location.href]);
  });
}

async function test_screen_orientation_lock() {
  try {
    await screen.orientation.lock('portrait');
  } catch (e) {
    assert_equals(
      e.name,
      'SecurityError',
      'orientation.lock() must throw a SecurityError in a fenced frame.');
    return;
  }
  assert_unreached('orientation.lock() must throw an error');
}

async function test_pointer_lock() {
  const canvas = document.createElement('canvas');
  document.body.appendChild(canvas);
  const pointerlockerror_promise = new Promise(resolve => {
    document.addEventListener('pointerlockerror', resolve);
  });
  try {
    await canvas.requestPointerLock();
  } catch (e) {
    assert_equals(
      e.name,
      'SecurityError',
      'orientation.lock() must throws a SecurityError in a fenced frame.');
    await pointerlockerror_promise;
    return;
  }
  assert_unreached('requestPointerLock() must fail in a fenced frame');
}
