summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/cookies/resources/cookie-test.js
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/cookies/resources/cookie-test.js')
-rw-r--r--testing/web-platform/tests/cookies/resources/cookie-test.js186
1 files changed, 186 insertions, 0 deletions
diff --git a/testing/web-platform/tests/cookies/resources/cookie-test.js b/testing/web-platform/tests/cookies/resources/cookie-test.js
new file mode 100644
index 0000000000..a909e4d72f
--- /dev/null
+++ b/testing/web-platform/tests/cookies/resources/cookie-test.js
@@ -0,0 +1,186 @@
+// getAndExpireCookiesForDefaultPathTest is a helper method to get and delete
+// cookies using echo-cookie.html.
+async function getAndExpireCookiesForDefaultPathTest() {
+ return new Promise((resolve, reject) => {
+ try {
+ const iframe = document.createElement('iframe');
+ iframe.style = 'display: none';
+ iframe.src = '/cookies/resources/echo-cookie.html';
+ iframe.addEventListener('load', (e) => {
+ const win = e.target.contentWindow;
+ const iframeCookies = win.getCookies();
+ win.expireCookies().then(() => {
+ document.documentElement.removeChild(iframe);
+ resolve(iframeCookies);
+ });
+ }, {once: true});
+ document.documentElement.appendChild(iframe);
+ } catch (e) {
+ reject(e);
+ }
+ });
+}
+
+// getAndExpireCookiesForRedirectTest is a helper method to get and delete
+// cookies that were set from a Location header redirect.
+async function getAndExpireCookiesForRedirectTest(location) {
+ return new Promise((resolve, reject) => {
+ try {
+ const iframe = document.createElement('iframe');
+ iframe.style = 'display: none';
+ iframe.src = location;
+ const listener = (e) => {
+ if (typeof e.data == 'object' && 'cookies' in e.data) {
+ window.removeEventListener('message', listener);
+ document.documentElement.removeChild(iframe);
+ resolve(e.data.cookies);
+ }
+ };
+ window.addEventListener('message', listener);
+ iframe.addEventListener('load', (e) => {
+ e.target.contentWindow.postMessage('getAndExpireCookiesForRedirectTest', '*');
+ }, {once: true});
+ document.documentElement.appendChild(iframe);
+ } catch (e) {
+ reject(e);
+ }
+ });
+}
+
+// httpCookieTest sets a `cookie` (via HTTP), then asserts it was or was not set
+// via `expectedValue` (via the DOM). Then cleans it up (via test driver). Most
+// tests do not set a Path attribute, so `defaultPath` defaults to true. If the
+// cookie values are expected to cause the HTTP request or response to fail, the
+// test can be made to pass when this happens via `allowFetchFailure`, which
+// defaults to false.
+//
+// `cookie` may be a single cookie string, or an array of cookie strings, where
+// the order of the array items represents the order of the Set-Cookie headers
+// sent by the server.
+//
+// Note: this function has a dependency on testdriver.js. Any test files calling
+// it should include testdriver.js and testdriver-vendor.js
+function httpCookieTest(cookie, expectedValue, name, defaultPath = true,
+ allowFetchFailure = false) {
+ return promise_test((t) => {
+ var skipAssertions = false;
+ return new Promise(async (resolve, reject) => {
+ // The result is ignored as we're expiring cookies for cleaning here.
+ await getAndExpireCookiesForDefaultPathTest();
+ await test_driver.delete_all_cookies();
+ t.add_cleanup(test_driver.delete_all_cookies);
+
+ let encodedCookie = encodeURIComponent(JSON.stringify(cookie));
+ try {
+ await fetch(`/cookies/resources/cookie.py?set=${encodedCookie}`);
+ } catch {
+ if (allowFetchFailure) {
+ skipAssertions = true;
+ resolve();
+ } else {
+ reject('Failed to fetch /cookies/resources/cookie.py');
+ }
+ }
+ let cookies = document.cookie;
+ if (defaultPath) {
+ // for the tests where a Path is set from the request-uri
+ // path, we need to go look for cookies in an iframe at that
+ // default path.
+ cookies = await getAndExpireCookiesForDefaultPathTest();
+ }
+ resolve(cookies);
+ }).then((cookies) => {
+ if (skipAssertions) {
+ return;
+ }
+ if (Boolean(expectedValue)) {
+ assert_equals(cookies, expectedValue, 'The cookie was set as expected.');
+ } else {
+ assert_equals(cookies, expectedValue, 'The cookie was rejected.');
+ }
+ });
+ }, name);
+}
+
+// This is a variation on httpCookieTest, where a redirect happens via
+// the Location header and we check to see if cookies are sent via
+// getRedirectedCookies
+//
+// Note: the locations targeted by this function have a dependency on
+// path-redirect-shared.js and should be sure to include it.
+function httpRedirectCookieTest(cookie, expectedValue, name, location) {
+ return promise_test(async (t) => {
+ // The result is ignored as we're expiring cookies for cleaning here.
+ await getAndExpireCookiesForRedirectTest(location);
+
+ const encodedCookie = encodeURIComponent(JSON.stringify(cookie));
+ const encodedLocation = encodeURIComponent(location);
+ const setParams = `?set=${encodedCookie}&location=${encodedLocation}`;
+ await fetch(`/cookies/resources/cookie.py${setParams}`);
+ // for the tests where a redirect happens, we need to head
+ // to that URI to get the cookies (and then delete them there)
+ const cookies = await getAndExpireCookiesForRedirectTest(location);
+ if (Boolean(expectedValue)) {
+ assert_equals(cookies, expectedValue, 'The cookie was set as expected.');
+ } else {
+ assert_equals(cookies, expectedValue, 'The cookie was rejected.');
+ }
+ }, name);
+}
+
+// Sets a `cookie` via the DOM, checks it against `expectedValue` via the DOM,
+// then cleans it up via the DOM. This is needed in cases where going through
+// HTTP headers may modify the cookie line (e.g. by stripping control
+// characters).
+//
+// Note: this function has a dependency on testdriver.js. Any test files calling
+// it should include testdriver.js and testdriver-vendor.js
+function domCookieTest(cookie, expectedValue, name) {
+ return promise_test(async (t) => {
+ await test_driver.delete_all_cookies();
+ t.add_cleanup(test_driver.delete_all_cookies);
+
+ if (typeof cookie === "string") {
+ document.cookie = cookie;
+ } else if (Array.isArray(cookie)) {
+ for (const singlecookie of cookie) {
+ document.cookie = singlecookie;
+ }
+ } else {
+ throw new Error('Unexpected type passed into domCookieTest as cookie: ' + typeof cookie);
+ }
+ let cookies = document.cookie;
+ assert_equals(cookies, expectedValue, Boolean(expectedValue) ?
+ 'The cookie was set as expected.' :
+ 'The cookie was rejected.');
+ }, name);
+}
+
+// Returns an array of control characters along with their ASCII codes. Control
+// characters are defined by RFC 5234 to be %x00-1F / %x7F.
+function getCtlCharacters() {
+ const ctlCodes = [...Array(0x20).keys()]
+ .concat([0x7F]);
+ return ctlCodes.map(i => ({ code: i, chr: String.fromCharCode(i) }))
+}
+
+// Returns a cookie string with name set to "t" * nameLength and value
+// set to "1" * valueLength. Passing in 0 for either allows for creating
+// a name- or value-less cookie.
+//
+// Note: Cookie length checking should ignore the "=".
+function cookieStringWithNameAndValueLengths(nameLength, valueLength) {
+ return `${"t".repeat(nameLength)}=${"1".repeat(valueLength)}`;
+}
+
+// Finds the root window.top.opener and directs test_driver commands to it.
+//
+// If you see a message like: "Error: Tried to run in a non-testharness window
+// without a call to set_test_context." then you probably need to call this.
+function setTestContextUsingRootWindow() {
+ let test_window = window.top;
+ while (test_window.opener && !test_window.opener.closed) {
+ test_window = test_window.opener.top;
+ }
+ test_driver.set_test_context(test_window);
+}