<!DOCTYPE html>
<title>DedicatedWorker: WorkerOptions 'credentials'</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script>
host_info = get_host_info();

// Determines the expected cookie value to be reported by a dedicated worker
// based on the given option. The worker reports an empty string as the actual
// cookie value if the cookie wasn't sent to the server. Otherwise, it's the
// value set by the headers file:
// "dedicated-worker-options-credentials.html.headers"
function DetermineExpectedCookieValue(options, config) {
  // Valid WorkerOptions and test config checking.
  if (config.origin !== 'same' && config.origin !== 'remote')
    assert_unreached('Invalid config.origin was specified: ' + config.origin);
  if (options.credentials && options.credentials !== 'omit' &&
      options.credentials !== 'same-origin' &&
      options.credentials !== 'include') {
    assert_unreached('Invalid credentials option was specified: ' +
                      options.credentials);
  }
  if (options.type !== 'classic' && options.type !== 'module')
    assert_unreached('Invalid type option was specified: ' + options.type);

  if (options.type === 'classic')
    return (config.origin === 'same') ? '1' : '';

  if (options.credentials === 'omit')
    return '';
  else if (options.credentials === 'include')
    return '1';
  else
    return (config.origin === 'same') ? '1' : '';
}

// Runs a credentials test with the given WorkerOptions.
//
// |options| is a WorkerOptions dict.
// |config| has options as follows:
//
//   config = {
//     fetchType: 'top-level' or 'descendant-static' or 'descendant-dynamic'
//     origin: 'remote' or 'same'
//   };
//
// - |config.fetchType| indicates the type of script to load for the test.
// - |config.origin| indicates same-origin-ness of the script to load.
function credentials_test(options, config, description) {
  promise_test(async () => {
    let workerURL, origin = config.origin;
    if (config.fetchType === 'top-level') {
      workerURL = 'resources/postmessage-credentials.py';
    } else if (config.fetchType === 'descendant-static') {
      workerURL =
        `resources/static-import-${origin}-origin-credentials-checker-worker.${origin === 'same' ? '' : 'sub.'}js`;
    } else if (config.fetchType === 'descendant-dynamic') {
      workerURL =
        `resources/dynamic-import-${origin}-origin-credentials-checker-worker.${origin === 'same' ? '' : 'sub.'}js`;
    } else {
      assert_unreached('Invalid config.fetchType: ' + config.fetchType);
    }

    const worker = new Worker(workerURL, options);

    // Wait until the worker sends the actual cookie value.
    const msg_event = await new Promise(resolve => worker.onmessage = resolve);

    const expectedCookieValue = DetermineExpectedCookieValue(options, config);
    assert_equals(msg_event.data, expectedCookieValue);
  }, description);
}

function init() {
  // Same-origin cookie is set up in the .headers file in this directory.
  promise_test(async () => {
    return fetch(
      `${host_info.HTTP_REMOTE_ORIGIN}/cookies/resources/set-cookie.py?name=COOKIE_NAME&path=/workers/modules/`,
      {
        mode: 'no-cors',
        credentials: 'include'
      });
  }, 'Test initialization: setting up cross-origin cookie');
}

init();

// Tests for module workers.

credentials_test(
    { type: 'module' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=module and default credentials option should ' +
    'behave as credentials=same-origin and send the credentials');

credentials_test(
    { credentials: 'omit', type: 'module' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=module and credentials=omit should not send the ' +
    'credentials');

credentials_test(
    { credentials: 'same-origin', type: 'module' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=module and credentials=same-origin should send ' +
    'the credentials');

credentials_test(
    { credentials: 'include', type: 'module' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=module and credentials=include should send the ' +
    'credentials');

// Tests for module worker static imports.

credentials_test(
    { type: 'module' },
    { fetchType: 'descendant-static', origin: 'same' },
    'new Worker() with type=module and default credentials option should ' +
    'behave as credentials=same-origin and send the credentials for ' +
    'same-origin static imports');

credentials_test(
    { credentials: 'omit', type: 'module' },
    { fetchType: 'descendant-static', origin: 'same' },
    'new Worker() with type=module and credentials=omit should not send the ' +
    'credentials for same-origin static imports');

credentials_test(
    { credentials: 'same-origin', type: 'module' },
    { fetchType: 'descendant-static', origin: 'same' },
    'new Worker() with type=module and credentials=same-origin should send ' +
    'the credentials for same-origin static imports');

credentials_test(
    { credentials: 'include', type: 'module' },
    { fetchType: 'descendant-static', origin: 'same' },
    'new Worker() with type=module and credentials=include should send the ' +
    'credentials for same-origin static imports');

credentials_test(
    { type: 'module' },
    { fetchType: 'descendant-static', origin: 'remote' },
    'new Worker() with type=module and default credentials option should ' +
    'behave as credentials=same-origin and not send the credentials for ' +
    'cross-origin static imports');

credentials_test(
    { credentials: 'omit', type: 'module' },
    { fetchType: 'descendant-static', origin: 'remote' },
    'new Worker() with type-module credentials=omit should not send the ' +
    'credentials for cross-origin static imports');

credentials_test(
    { credentials: 'same-origin', type: 'module' },
    { fetchType: 'descendant-static', origin: 'remote' },
    'new Worker() with type=module and credentials=same-origin should not ' +
    'send the credentials for cross-origin static imports');

credentials_test(
    { credentials: 'include', type: 'module' },
    { fetchType: 'descendant-static', origin: 'remote' },
    'new Worker() with type=module and credentials=include should send the ' +
    'credentials for cross-origin static imports');

// Tests for module worker dynamic imports.

credentials_test(
    { type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=module and default credentials option should ' +
    'behave as credentials=same-origin and send the credentials for ' +
    'same-origin dynamic imports');

credentials_test(
    { credentials: 'omit', type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=module and credentials=omit should not send the ' +
    'credentials for same-origin dynamic imports');

credentials_test(
    { credentials: 'same-origin', type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=module and credentials=same-origin should send ' +
    'the credentials for same-origin dynamic imports');

credentials_test(
    { credentials: 'include', type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=module and credentials=include should send the ' +
    'credentials for same-origin dynamic imports');

credentials_test(
    { type: 'module'},
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=module and default credentials option should ' +
    'behave as credentials=same-origin and not send the credentials for ' +
    'cross-origin dynamic imports');

credentials_test(
    { credentials: 'omit', type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type-module credentials=omit should not send the ' +
    'credentials for cross-origin dynamic imports');

credentials_test(
    { credentials: 'same-origin', type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=module and credentials=same-origin should not ' +
    'send the credentials for cross-origin dynamic imports');

credentials_test(
    { credentials: 'include', type: 'module' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=module and credentials=include should send the ' +
    'credentials for cross-origin dynamic imports');

// Tests for classic workers.
// TODO(domfarolino): Maybe move classic worker tests up a directory?

credentials_test(
    { type: 'classic' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=classic should always send the credentials ' +
    'regardless of the credentials option (default).');

credentials_test(
    { credentials: 'omit', type: 'classic' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=classic should always send the credentials ' +
    'regardless of the credentials option (omit).');

credentials_test(
    { credentials: 'same-origin', type: 'classic' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=classic should always send the credentials ' +
    'regardless of the credentials option (same-origin).');

credentials_test(
    { credentials: 'include', type: 'classic' },
    { fetchType: 'top-level', origin: 'same' },
    'new Worker() with type=classic should always send the credentials ' +
    'regardless of the credentials option (include).');

// Tests for classic worker dynamic imports.

credentials_test(
    { type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=classic should always send the credentials for ' +
    'same-origin dynamic imports regardless of the credentials option ' +
    '(default).');

credentials_test(
    { credentials: 'omit', type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=classic should always send the credentials for ' +
    'same-origin dynamic imports regardless of the credentials option (omit).');

credentials_test(
    { credentials: 'same-origin', type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=classic should always send the credentials for ' +
    'same-origin dynamic imports regardless of the credentials option ' +
    '(same-origin).');

credentials_test(
    { credentials: 'include', type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'same' },
    'new Worker() with type=classic should always send the credentials for ' +
    'same-origin dynamic imports regardless of the credentials option ' +
    '(include).');

credentials_test(
    { type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=classic should never send the credentials for ' +
    'cross-origin dynamic imports regardless of the credentials option ' +
    '(default).');

credentials_test(
    { credentials: 'omit', type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=classic should never send the credentials for ' +
    'cross-origin dynamic imports regardless of the credentials option ' +
    '(omit).');

credentials_test(
    { credentials: 'same-origin', type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=classic should never send the credentials for ' +
    'cross-origin dynamic imports regardless of the credentials option ' +
    '(same-origin).');

credentials_test(
    { credentials: 'include', type: 'classic' },
    { fetchType: 'descendant-dynamic', origin: 'remote' },
    'new Worker() with type=classic should never send the credentials for ' +
    'cross-origin dynamic imports regardless of the credentials option ' +
    '(include).');

</script>
