# testharness.js tutorial Let's say you've discovered that WPT doesn't have any tests for how [the Fetch API](https://fetch.spec.whatwg.org/) sets cookies from an HTTP response. This tutorial will guide you through the process of writing a test for the web-platform, verifying it, and submitting it back to WPT. Although it includes some very brief instructions on using git, you can find more guidance in [the tutorial for git and GitHub](github-intro). WPT's testharness.js is a framework designed to help people write tests for the web platform's JavaScript APIs. [The testharness.js reference page](testharness) describes the framework in the abstract, but for the purposes of this guide, we'll only consider the features we need to test the behavior of `fetch`. ```eval_rst .. contents:: Table of Contents :depth: 3 :local: :backlinks: none ``` ## Setting up your workspace To make sure you have the latest code, first type the following into a terminal located in the root of the WPT git repository: $ git fetch git@github.com:web-platform-tests/wpt.git Next, we need a place to store the change set we're about to author. Here's how to create a new git branch named `fetch-cookie` from the revision of WPT we just downloaded: $ git checkout -b fetch-cookie FETCH_HEAD The tests we're going to write will rely on special abilities of the WPT server, so you'll also need to [configure your system to run WPT](../running-tests/from-local-system) before you continue. With that out of the way, you're ready to create your patch. ## Writing a subtest The first thing we'll do is configure the server to respond to a certain request by setting a cookie. Once that's done, we'll be able to make the request with `fetch` and verify that it interpreted the response correctly. We'll configure the server with an "asis" file. That's the WPT convention for controlling the contents of an HTTP response. [You can read more about it here](server-features), but for now, we'll save the following text into a file named `set-cookie.asis` in the `fetch/api/basic/` directory of WPT: ``` HTTP/1.1 204 No Content Set-Cookie: test1=t1 ``` With this in place, any requests to `/fetch/api/basic/set-cookie.asis` will receive an HTTP 204 response that sets the cookie named `test1`. When writing more tests in the future, you may want the server to behave more dynamically. In that case, [you can write Python code to control how the server responds](python-handlers/index). Now, we can write the test! Create a new file named `set-cookie.html` in the same directory and insert the following text: ```html fetch: setting cookies ``` Let's step through each part of this file. - ```html ``` We explicitly set the DOCTYPE and character set to be sure that browsers don't infer them to be something we aren't expecting. We're omitting the `` and `` tags. That's a common practice in WPT, preferred because it makes tests more concise. - ```html fetch: setting cookies ``` The document's title should succinctly describe the feature under test. - ```html ``` These two ` ``` This script uses the testharness.js function `promise_test` to define a "subtest". We're using that because the behavior we're testing is asynchronous. By returning a Promise value, we tell the harness to wait until that Promise settles. The harness will report that the test has passed if the Promise is fulfilled, and it will report that the test has failed if the Promise is rejected. We invoke the global `fetch` function to exercise the "behavior under test," and in the fulfillment handler, we verify that the expected cookie is set. We're using the testharness.js `assert_equals` function to verify that the value is correct; the function will throw an error otherwise. That will cause the Promise to be rejected, and *that* will cause the harness to report a failure. If you run the server according to the instructions in [the guide for local configuration](../running-tests/from-local-system), you can access the test at [http://web-platform.test:8000/fetch/api/basic/set-cookie.html](http://web-platform.test:8000/fetch/api/basic/set-cookie.html.). You should see something like this: ![](../assets/testharness-tutorial-test-screenshot-1.png "screen shot of testharness.js reporting the test results") ## Refining the subtest We'd like to test a little more about `fetch` and cookies, but before we do, there are some improvements we can make to what we've written so far. For instance, we should remove the cookie after the subtest is complete. This ensures a consistent state for any additional subtests we may add and also for any tests that follow. We'll use the `add_cleanup` method to ensure that the cookie is deleted even if the test fails. ```diff -promise_test(function() { +promise_test(function(t) { + t.add_cleanup(function() { + document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + }); + return fetch('thing.asis') .then(function() { assert_equals(document.cookie, 'test1=t1'); }); }); ``` Although we'd prefer it if there were no other cookies defined during our test, we shouldn't take that for granted. As written, the test will fail if the `document.cookie` includes additional cookies. We'll use slightly more complicated logic to test for the presence of the expected cookie. ```diff promise_test(function(t) { t.add_cleanup(function() { document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;'; }); return fetch('thing.asis') .then(function() { - assert_equals(document.cookie, 'test1=t1'); + assert_true(/(^|; )test1=t1($|;)/.test(document.cookie); }); }); ``` In the screen shot above, the subtest's result was reported using the document's title, "fetch: setting cookies". Since we expect to add another subtest, we should give this one a more specific name: ```diff promise_test(function(t) { t.add_cleanup(function() { document.cookie = 'test1=;expires=Thu, 01 Jan 1970 00:00:01 GMT;'; }); return fetch('thing.asis') .then(function() { assert_true(/(^|; )test1=t1($|;)/.test(document.cookie)); }); -}); +}, 'cookie set for successful request'); ``` ## Writing a second subtest There are many things we might want to verify about how `fetch` sets cookies. For instance, it should *not* set a cookie if the request fails due to cross-origin security restrictions. Let's write a subtest which verifies that. We'll add another ` + ``` `get-host-info.sub.js` is a general-purpose script provided by WPT. It's designed to help with testing cross-domain functionality. Since it's stored in WPT's `common/` directory, tests from all sorts of specifications rely on it. Next, we'll define the new subtest inside the same `