<!DOCTYPE HTML>
<html>
<head>
  <title>Test for content script caching</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
  <script type="text/javascript" src="head.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>

<script type="text/javascript">
"use strict";

// This file defines content scripts.

const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";

add_task(async function test_contentscript_cache() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      content_scripts: [{
        "matches": ["http://mochi.test/*/file_sample.html"],
        "js": ["content_script.js"],
        "run_at": "document_start",
      }],

      permissions: ["<all_urls>", "tabs"],
    },

    async background() {
      // Force our extension instance to be initialized for the current content process.
      await browser.tabs.insertCSS({code: ""});

      browser.test.sendMessage("origin", location.origin);
    },

    files: {
      "content_script.js": function() {
        browser.test.sendMessage("content-script-loaded");
      },
    },
  });

  await extension.startup();

  let origin = await extension.awaitMessage("origin");
  let scriptUrl = `${origin}/content_script.js`;

  const { ExtensionProcessScript } = SpecialPowers.ChromeUtils.import(
    "resource://gre/modules/ExtensionProcessScript.jsm"
  );
  let ext = ExtensionProcessScript.getExtensionChild(extension.id);

  ext.staticScripts.expiryTimeout = 3000;
  is(ext.staticScripts.size, 0, "Should have no cached scripts");

  let win = window.open(`${BASE}/file_sample.html`);
  await extension.awaitMessage("content-script-loaded");

  if (AppConstants.platform !== "android") {
    is(ext.staticScripts.size, 1, "Should have one cached script");
    ok(ext.staticScripts.has(scriptUrl), "Script cache should contain script URL");
  }

  let chromeScript, chromeScriptDone;
  let { appinfo } = SpecialPowers.Services;
  if (appinfo.processType === appinfo.PROCESS_TYPE_CONTENT) {
    /* globals addMessageListener, assert */
    chromeScript = SpecialPowers.loadChromeScript(() => {
      /* eslint-env mozilla/chrome-script */
      addMessageListener("check-script-cache", extensionId => {
        const { ExtensionProcessScript } = ChromeUtils.import(
          "resource://gre/modules/ExtensionProcessScript.jsm"
        );
        let ext = ExtensionProcessScript.getExtensionChild(extensionId);

        if (ext && ext.staticScripts) {
          assert.equal(ext.staticScripts.size, 0, "Should have no cached scripts in the parent process");
        }

        sendAsyncMessage("done");
      });
    });
    chromeScript.sendAsyncMessage("check-script-cache", extension.id);
    chromeScriptDone = chromeScript.promiseOneMessage("done");
  }

  SimpleTest.requestFlakyTimeout("Required to test expiry timeout");
  await new Promise(resolve => setTimeout(resolve, 3000));
  is(ext.staticScripts.size, 0, "Should have no cached scripts");

  if (chromeScript) {
    await chromeScriptDone;
    chromeScript.destroy();
  }

  win.close();

  win = window.open(`${BASE}/file_sample.html`);
  await extension.awaitMessage("content-script-loaded");

  is(ext.staticScripts.size, 1, "Should have one cached script");
  ok(ext.staticScripts.has(scriptUrl));

  SpecialPowers.Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");

  is(ext.staticScripts.size, 0, "Should have no cached scripts after heap-minimize");

  win.close();

  await extension.unload();
});
</script>

</body>
</html>
