summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/resources/docs/idlharness.md
blob: 141077b3a72a7a0e5beb92a31981421966bb7e58 (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
## Introduction ##

`idlharness.js` automatically generates browser tests for WebIDL interfaces, using
the testharness.js framework.  To use, first include the following:

```html
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
```

Then you'll need some type of IDLs.  Here's some script that can be run on a
spec written in HTML, which will grab all the elements with `class="idl"`,
concatenate them, and replace the body so you can copy-paste:

```js
var s = "";
[].forEach.call(document.getElementsByClassName("idl"), function(idl) {
  //https://www.w3.org/Bugs/Public/show_bug.cgi?id=14914
  if (!idl.classList.contains("extract"))
  {
    s += idl.textContent + "\n\n";
  }
});
document.body.innerHTML = '<pre></pre>';
document.body.firstChild.textContent = s;
```

Once you have that, put it in your script somehow.  The easiest way is to
embed it literally in an HTML file with `<script type=text/plain>` or similar,
so that you don't have to do any escaping.  Another possibility is to put it
in a separate .idl file that's fetched via XHR or similar.  Sample usage:

```js
var idl_array = new IdlArray();
idl_array.add_untested_idls("interface Node { readonly attribute DOMString nodeName; };");
idl_array.add_idls("interface Document : Node { readonly attribute DOMString URL; };");
idl_array.add_objects({Document: ["document"]});
idl_array.test();
```

This tests that `window.Document` exists and meets all the requirements of
WebIDL.  It also tests that window.document (the result of evaluating the
string "document") has URL and nodeName properties that behave as they
should, and otherwise meets WebIDL's requirements for an object whose
primary interface is Document.  It does not test that window.Node exists,
which is what you want if the Node interface is already tested in some other
specification's suite and your specification only extends or refers to it.
Of course, each IDL string can define many different things, and calls to
add_objects() can register many different objects for different interfaces:
this is a very simple example.

## Public methods of IdlArray ##

IdlArray objects can be obtained with `new IdlArray()`.  Anything not
documented in this section should be considered an implementation detail,
and outside callers should not use it.

### `add_idls(idl_string)`
  Parses `idl_string` (throwing on parse error) and adds the results to the
  IdlArray.  All the definitions will be tested when you run test().  If
  some of the definitions refer to other definitions, those must be present
  too.  For instance, if `idl_string` says that `Document` inherits from `Node`,
  the `Node` interface must also have been provided in some call to `add_idls()`
  or `add_untested_idls()`.

### `add_untested_idls(idl_string)`
  Like `add_idls()`, but the definitions will not be tested.  If an untested
  interface is added and then extended with a tested partial interface, the
  members of the partial interface will still be tested.  Also, all the
  members will still be tested for objects added with `add_objects()`, because
  you probably want to test that (for instance) window.document has all the
  properties from `Node`, not just `Document`, even if the `Node` interface itself
  is tested in a different test suite.

### `add_objects(dict)`
  `dict` should be an object whose keys are the names of interfaces or
  exceptions, and whose values are arrays of strings.  When an interface or
  exception is tested, every string registered for it with `add_objects()`
  will be evaluated, and tests will be run on the result to verify that it
  correctly implements that interface or exception.  This is the only way to
  test anything about `[NoInterfaceObject]` interfaces, and there are many
  tests that can't be run on any interface without an object to fiddle with.

  The interface has to be the *primary* interface of all the objects
  provided.  For example, don't pass `{Node: ["document"]}`, but rather
  `{Document: ["document"]}`.  Assuming the `Document` interface was declared to
  inherit from `Node`, this will automatically test that document implements
  the `Node` interface too.

  Warning: methods will be called on any provided objects, in a manner that
  WebIDL requires be safe.  For instance, if a method has mandatory
  arguments, the test suite will try calling it with too few arguments to
  see if it throws an exception.  If an implementation incorrectly runs the
  function instead of throwing, this might have side effects, possibly even
  preventing the test suite from running correctly.

### `prevent_multiple_testing(name)`
  This is a niche method for use in case you're testing many objects that
  implement the same interfaces, and don't want to retest the same
  interfaces every single time.  For instance, HTML defines many interfaces
  that all inherit from `HTMLElement`, so the HTML test suite has something
  like

```js
.add_objects({
  HTMLHtmlElement: ['document.documentElement'],
  HTMLHeadElement: ['document.head'],
  HTMLBodyElement: ['document.body'],
  ...
})
```

  and so on for dozens of element types.  This would mean that it would
  retest that each and every one of those elements implements `HTMLElement`,
  `Element`, and `Node`, which would be thousands of basically redundant tests.
  The test suite therefore calls `prevent_multiple_testing("HTMLElement")`.
  This means that once one object has been tested to implement `HTMLElement`
  and its ancestors, no other object will be.  Thus in the example code
  above, the harness would test that `document.documentElement` correctly
  implements `HTMLHtmlElement`, `HTMLElement`, `Element`, and `Node`; but
  `document.head` would only be tested for `HTMLHeadElement`, and so on for
  further objects.

### `test()`
  Run all tests.  This should be called after you've called all other
  methods to add IDLs and objects.