14. JSDoc

In N4JS, comments starting with two asterisks (in /** .. */) are interpreted as documentation comments. The format is similar to JavaDoc or Google Closure annotations.

14.1. General N4JSDoc Features

We distinguish between line and inline tags. The format of the content of a tag is specific to the tag. Most line tags, however, contain a description which is simply multiline text with nested inline tags. Every comment may start with a description.

14.1.1. Provided Inline Tags

14.1.1.1. @code

Small code snippet, not validated yet.

Link to a type of element, not validated or supported in navigation yet.

14.2. N4JSdoc for User Projects

14.2.1. Standard Tags

14.2.1.1. @author

Name of author, repeat for multiple authors. Name of author is not validated.

14.2.1.2. @param

Parameter description, not validated at the moment.

14.2.1.3. @return

Return description, not validated at the moment.

The following tags are supposed to be used only in tests.

14.2.2.1. @testee

Link to type (maybe a function) or member tested by the test.

Req. IDE-172: @testee Semantics (ver. 1)

  1. Tag can be only used on either

    1. methods annotated with @Test

    2. classes in test projects or folders, cf. @testeeFromType.

  2. Tag requires a single argument, which is a fully qualified name to a type, including the module specifier. The format is as follows: moduleSpecifier '.' typeName ( ('.'|'#') memberName)?

  3. Tag is not repeatable, that is a single test method (or class) can refer to only one testee.

  4. Tag precedes the reqid tag, i.e., if a @testee is specified, the reqid will be ignored.

Example 109. @testee

The target element is to be fully qualified including the module specifier. The module specifier is simply the source folder relative path name with forward slashes. Type and element are added to that using dot as a separator. For example:

/**
 * @testee some/package/Module.Type.member
 */
14.2.2.2. @testeeFromType

Instead of directly linking a test method to a testee, the testee is to be derived from the linked testee of the test class. This is useful if a base test class is defined with generic tests, e.g., for testing methods defined in an interface and implemented by some classes. This base test class is then extended by concrete test classes, correctly setting up the test fixture, e.g., creating instances of some classes implementing the interfaces tested in the base class.

Example 110. Usage of testeeFromType

In the following example, the is used. This tag will lead to a test documentation for B.foo and C.foo.

abstract class Base {
    /**
     * @testeeFromType
     */
    @Test testFoo() {..}
}

/**
 * @testee B.foo
 */
class TestB extends Base {}

/**
 * @testee C.foo
 */
class TestC extends Base {}
The resulting spec has to be double-checked for consistency since it is easily possible that too many constraints are generated.
14.2.2.3. @testeeType and @testeeMember

Specifying the testee at the test method directly should be sufficient for most cases. The @testeeFromType tag already provides support for some cases in which a base test class is reused by subtypes. This case usually only works if the base test class tests a single method only. If the base test class tests several methods and if a sub test class only provides a different fixture, this mechanism is not sufficient. For that purpose, the two tags @testeeFromType and @@testeeMember are to be used. They enable the separation of a test related to a specific member and the concrete receiver type of the tested member.

The @testeeType is to defined in the test class JSDoc (actually, it is not recognized when defined in a member JSDoc). The @testeeMember is specified in the test method JSDoc. The "real" testee is then computed from the testee type and the testee method.

1. This only works for instance members, so far!
2. There is no validation for invalid combinations!
Example 111. testeeType and testeeMethod

Assume the following testees:

class A {
    foo(): void {..}
    bar(): void { .. this.foo(); ..}
}
class B extends A {
    @Override foo() { .. }
}

Assume that the tests have to ensure the same semantics for bar, which is maybe changed by a wrong implementation of foo. That is, bar is to be tested in case of the receiver type A and B. This can be achieved by the following tests:

/**
 * @testeeType A.A
 */
class ATest {
    fixture(): A { return new A(); }

    /**
     * @testeeMember bar
     */
    @Test testBar(): void { assertBehavior( fixture().bar() ); }
}
/**
 * @testeeType B.B
 */
class BTest extends ATest {
    @Override fixture(): B { return new B(); }
}

This actually defines two tests, which is also recognized by the spec exporter:

  1. testBar for a receiver of type A:

    ATest's JSDoc @testeeType + ATest.testBar's JSDoc @testeeMember = testee A.A.bar

  2. testBar for a receiver of type B:

    BTest's JSDoc @testeeType + ATest.testBar's JSDoc @testeeMember = testee B.B.bar

In all cases when @testeeFromType or @testeeType/@testeeMember is used, the resulting spec has to be double-checked for consistency. Consider if the multiplication of spec constraints is truly required, in particular if the original semantics of a method is not changed. Remember: It is possible to write API tests and omit the spec constraint generation simply by not adding the testee links.
Example 112. testeeType and testeeMethod with omitted constraints

Assume testees similar as in testeeType and testeeMethod. Since the semantics of bar is not changed in B, it is probably not necessary to generate the same constraint in the documentation for bar twice (one in the section for class A and another one in the section of class B). Still, we want the test to be executed for both receivers. This is how it is achieved:

abstract class BaseTest {
    abstract fixture(): A;

    /**
     * @testeeMember bar
     */
    @Test testBar(): void { assertBehavior( fixture().bar() ); }
}

/**
 * @testeeType A.A
 */
class ATest extends BaseTest {
    fixture(): A { return new A(); }
}

class BTest extends BaseTest {
    @Override fixture(): B { return new B(); }
}

This actually defines two tests as in the previous example. Only one constraint is created in the spec by the spec exporter:

  1. testBar for a receiver of type A:
    ATest's JSDoc @testeeType + BaseTest.testBar's JSDoc @testeeMember = testee A.A.bar

Although a test for receiver of type B is run, no additional constraint is created since there is no @testeeType available neither in BTest nor in BaseTest.

14.2.2.4. @reqid in Tests

ID of feature used in JSDoc for the requirements section. If no testee (via one of the tags above) is given, then the test is linked to the requirement with given id.

14.3. N4JSDoc for API and Implementation Projects

The following tags are supposed to be used in API and implementation projects.

14.3.1. @apiNote

Simple note that is shown in the API compare view.

14.3.2. API Project Tags

The following tags are supposed to be used in API projects only.

14.3.2.1. @apiState

State of type or member definition, e.g., stable or draft. This can be used to define a history. In this case, the tag has to be repeated. For example:

/**
 * @apiState stable (WK)
 * @apiState reviewed (JvP)
 */

Quick Links