summaryrefslogtreecommitdiffstats
path: root/dom/tests/browser/browser_persist_cross_origin_iframe.js
blob: 94a9a74af787f3784baa6b03b6890654a94dd7fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const TEST_PATH = getRootDirectory(gTestPath).replace(
  "chrome://mochitests/content",
  "https://example.org"
);
const TEST_PATH2 = getRootDirectory(gTestPath).replace(
  "chrome://mochitests/content",
  "https://example.com"
);

var MockFilePicker = SpecialPowers.MockFilePicker;
MockFilePicker.init(window);

registerCleanupFunction(async function () {
  info("Running the cleanup code");
  MockFilePicker.cleanup();
  if (gTestDir && gTestDir.exists()) {
    // On Windows, sometimes nsIFile.remove() throws, probably because we're
    // still writing to the directory we're trying to remove, despite
    // waiting for the download to complete. Just retry a bit later...
    let succeeded = false;
    while (!succeeded) {
      try {
        gTestDir.remove(true);
        succeeded = true;
      } catch (ex) {
        await new Promise(requestAnimationFrame);
      }
    }
  }
});

let gTestDir = null;

function createTemporarySaveDirectory() {
  var saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
  saveDir.append("testsavedir");
  if (!saveDir.exists()) {
    saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
  }
  return saveDir;
}

function canonicalizeExtension(str) {
  return str.replace(/\.htm$/, ".html");
}

function checkContents(dir, expected, str) {
  let stack = [dir];
  let files = [];
  while (stack.length) {
    for (let file of stack.pop().directoryEntries) {
      if (file.isDirectory()) {
        stack.push(file);
      }

      let path = canonicalizeExtension(file.getRelativePath(dir));
      files.push(path);
    }
  }

  SimpleTest.isDeeply(
    files.sort(),
    expected.sort(),
    str + "Should contain downloaded files in correct place."
  );
}

async function addFrame(browser, path, selector) {
  await SpecialPowers.spawn(
    browser,
    [path, selector],
    async function (path, selector) {
      let document = content.document;
      let target = document.querySelector(selector);
      if (content.HTMLIFrameElement.isInstance(target)) {
        document = target.contentDocument;
        target = document.body;
      }
      let element = document.createElement("iframe");
      element.src = path;
      await new Promise(resolve => {
        element.onload = resolve;
        target.appendChild(element);
      });
    }
  );
}

async function handleResult(expected, str) {
  let dls = await Downloads.getList(Downloads.PUBLIC);
  return new Promise((resolve, reject) => {
    dls.addView({
      onDownloadChanged(download) {
        if (download.succeeded) {
          checkContents(gTestDir, expected, str);

          dls.removeView(this);
          dls.removeFinished();
          resolve();
        } else if (download.error) {
          reject("Download failed");
        }
      },
    });
  });
}

add_task(async function () {
  await BrowserTestUtils.withNewTab(
    TEST_PATH + "image.html",
    async function (browser) {
      await addFrame(browser, TEST_PATH + "image.html", "body");
      await addFrame(browser, TEST_PATH2 + "image.html", "body>iframe");

      gTestDir = createTemporarySaveDirectory();

      MockFilePicker.displayDirectory = gTestDir;
      MockFilePicker.showCallback = function (fp) {
        let destFile = gTestDir.clone();
        destFile.append("first.html");
        MockFilePicker.setFiles([destFile]);
        MockFilePicker.filterIndex = 0; // kSaveAsType_Complete
      };

      let expected = [
        "first.html",
        "first_files",
        "first_files/image.html",
        "first_files/dummy.png",
        "first_files/image_data",
        "first_files/image_data/image.html",
        "first_files/image_data/image_data",
        "first_files/image_data/image_data/dummy.png",
      ];

      // This saves the top-level document contained in `browser`
      saveBrowser(browser);
      await handleResult(expected, "Check toplevel: ");

      // Instead of deleting previously saved files, we update our list
      // of expected files for the next part of the test. To not clash
      // we make sure to save to a different file name.
      expected = expected.concat([
        "second.html",
        "second_files",
        "second_files/dummy.png",
        "second_files/image.html",
        "second_files/image_data",
        "second_files/image_data/dummy.png",
      ]);

      MockFilePicker.showCallback = function (fp) {
        let destFile = gTestDir.clone();
        destFile.append("second.html");
        MockFilePicker.setFiles([destFile]);
        MockFilePicker.filterIndex = 0; // kSaveAsType_Complete
      };

      // This saves the sub-document of the iframe contained in the
      // top-level document, as indicated by passing a child browsing
      // context as target for the save.
      saveBrowser(browser, false, browser.browsingContext.children[0]);
      await handleResult(expected, "Check subframe: ");

      // Instead of deleting previously saved files, we update our list
      // of expected files for the next part of the test. To not clash
      // we make sure to save to a different file name.
      expected = expected.concat([
        "third.html",
        "third_files",
        "third_files/dummy.png",
      ]);

      MockFilePicker.showCallback = function (fp) {
        let destFile = gTestDir.clone();
        destFile.append("third.html");
        MockFilePicker.setFiles([destFile]);
        MockFilePicker.filterIndex = 0; // kSaveAsType_Complete
      };

      // This saves the sub-document of the iframe contained in the
      // first sub-document, as indicated by passing a child browsing
      // context as target for the save. That frame is special, because
      // it's cross-process.
      saveBrowser(
        browser,
        false,
        browser.browsingContext.children[0].children[0]
      );
      await handleResult(expected, "Check subframe: ");
    }
  );
});