summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/document-metadata/the-link-element/resources/link-load-error-events.sub.js
blob: 33c8709579e3b341b5455e73780244c6d8bb1704 (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
/**
 * This is the guts of the load/error event tests for <link rel="stylesheet">.
 *
 * We have a list of tests each of which is an object containing: href value,
 * expected load success boolean, test description.  Href values are set up in
 * such a way that we guarantee that all stylesheet URLs are unique.  This
 * avoids issues around caching of sheets based on URL.
 */

// Our URLs are random, so we don't use them in error messages by
// default, but enable doing it if someone wants to debug things.
const DEBUG_URLS = false;

var isHttps = location.protocol == "https:";

var tests = [
  // Basic tests
  {
    href: existingSheet(),
    success: true,
    description: "Basic load of stylesheet",
  },
  {
    href: nonexistentSheet(),
    success: false,
    description: "Attempted load of nonexistent stylesheet",
  },
  {
    href: `data:text/css,@import url("${existingSheet()}")`,
    success: true,
    description: "Import of stylesheet",
  },
  {
    href: `data:text/css,@import url("${nonexistentSheet()}")`,
    success: false,
    description: "Import of nonexistent stylesheet",
  },
  {
    href: `data:text/css,@import url("data:text/css,@import url('${existingSheet()}')")`,
    success: true,
    description: "Import of import of stylesheet",
  },
  {
    href: `data:text/css,@import url("data:text/css,@import url('${nonexistentSheet()}')")`,
    success: false,
    description: "Import of import of nonexistent stylesheet",
  },

  // Non-CSS-response tests.
  {
    href: makeUnique(""),
    success: false,
    description: "Load of non-CSS stylesheet",
  },
  {
    href: `data:text/css,@import url("${makeUnique("")}")`,
    success: false,
    description: "Import of non-CSS stylesheet",
  },
  {
    href: `data:text/css,@import url("data:text/css,@import url('${makeUnique("")}')")`,
    success: false,
    description: "Import of import of non-CSS stylesheet",
  },

  // http:// tests, to test what happens with mixed content blocking.
  {
    href: httpSheet(),
    success: !isHttps,
    description: "Load of http:// stylesheet",
  },
  {
    href: `data:text/css,@import url("${httpSheet()}")`,
    success: !isHttps,
    description: "Import of http:// stylesheet",
  },
  {
    href: `data:text/css,@import url("data:text/css,@import url('${httpSheet()}')")`,
    success: !isHttps,
    description: "Import of import of http:// stylesheet",
  },

  // https:// tests just as a control
  {
    href: httpsSheet(),
    success: true,
    description: "Load of https:// stylesheet",
  },
  {
    href: `data:text/css,@import url("${httpsSheet()}")`,
    success: true,
    description: "Import of https:// stylesheet",
  },
  {
    href: `data:text/css,@import url("data:text/css,@import url('${httpsSheet()}')")`,
    success: true,
    description: "Import of import of https:// stylesheet",
  },

  // Tests with multiple imports some of which are slow and some are fast.
  {
    href: `data:text/css,@import url("${slowResponse(existingSheet())}"); @import url("${nonexistentSheet()}");`,
    success: false,
    description: "Slow successful import, fast failing import",
  },
  {
    href: `data:text/css,@import url("${existingSheet()}"); @import url("${slowResponse(nonexistentSheet())}");`,
    success: false,
    description: "Fast successful import, slow failing import",
  }
];

// Note: Here we really do need to use "let" at least for the href,
// because we lazily evaluate it in the unreached cases.
for (var test of tests) {
  let {href, success, description} = test;
  var t = async_test(description);
  var link = document.createElement("link");
  link.rel = "stylesheet";
  hrefString = DEBUG_URLS ? `: ${href}` : "";
  if (success) {
    link.onload = t.step_func_done(() => {});
    link.onerror = t.step_func_done(() => assert_unreached(`error fired when load expected${hrefString}`) );
  } else {
    link.onerror = t.step_func_done(() => {});
    link.onload = t.step_func_done(() => assert_unreached(`load fired when error expected${hrefString}`) );
  }
  link.href = href;
  document.head.appendChild(link);
}

/* Utility function */
function makeUnique(url) {
  // Make sure we copy here, even if the thing coming in is a URL, so we don't
  // mutate our caller's data.
  url = new URL(url, location.href);
  // We want to generate a unique URI to avoid the various caches browsers have
  // for stylesheets.  We don't want to just use a counter, because that would
  // not be robust to the test being reloaded or othewise run multiple times
  // without a browser restart.  We don't want to use timstamps, because those
  // are not likely to be unique across calls to this function, especially given
  // the degraded timer resolution browsers have due to Spectre.
  //
  // So just fall back on Math.random() and assume it can't duplicate values.
  url.searchParams.append("r", Math.random());
  return url;
}

function existingSheet() {
  return makeUnique("resources/good.css");
}

/**
 * Function the add values to the "pipe" search param.  See
 * http://wptserve.readthedocs.io/en/latest/pipes.html for why one would do
 * this.  Because this param uses a weird '|'-separated syntax instead of just
 * using multiple params with the same name, we need some manual code to munge
 * the value properly.
 */
function addPipe(url, pipeVal) {
  url = new URL(url, location.href);
  var params = url.searchParams;
  var oldVal = params.get("pipe");
  if (oldVal) {
    params.set("pipe", oldVal + "|" + pipeVal);
  } else {
    params.set("pipe", pipeVal);
  }
  return url;
}

function nonexistentSheet() {
  return addPipe(existingSheet(), "status(404)");
}

function httpSheet() {
  var url = existingSheet();
  url.protocol = "http";
  url.port = {{ports[http][0]}};
  return url;
}

function httpsSheet() {
  var url = existingSheet();
  url.protocol = "https";
  url.port = {{ports[https][0]}};
  return url;
}

function slowResponse(url) {
  return addPipe(url, "trickle(d1)");
}