Web Apps in TDD, Appendix, the User

Here’s the User class and its collaborators as it is right now. It is a bit more evolved than its original form : when I first wrote it, all of the logic was in the User itself as I had no need to evaluate Javascript outside of html, later I separated the two responsibilities (parsing xml/html and evaluating Javascript) since I had a need to evaluate Javascript no matter where.

public class User {
    private final JavaScript javaScript = new JavaScript();
    private final Result result = new Result();

    public User() {

    public User lookAt(String htmlPage) {
        JavaScriptSource source = new XomJavaScriptSource(htmlPage);
        return this;

    public String currentSight() {
        return result.nextValue();

    private void triggerOnLoad() {
        javaScript.evaluateScript("window.onload();", "onload");


And here’s “JavaScript”, which manages everything Rhino-related.

public class JavaScript {
    private final Context context;
    private final ScriptableObject scope;

    public JavaScript() {
        context = Context.enter();
        scope = context.initStandardObjects();

    public Object valueOf(String variableName) {
        return scope.get(variableName);

    public void evaluateScript(String script, String scriptName) {
        context.evaluateString(scope, script, scriptName, 1, null);

    public void evaluateScript(String script) {
        evaluateScript(script, "script");

    public void evaluateFile(String sourceFileName) {
        try {
            context.evaluateReader(scope, read(sourceFileName), sourceFileName, 1, null);
        } catch (IOException e) {
            throw new RuntimeException(e);

    private InputStreamReader read(String sourceFileName) {
        return new InputStreamReader(getClass().getClassLoader().getResourceAsStream(sourceFileName));

This is “Result”, which extracts values from the results array in Javascript.

public class Result {
    private NativeArray output = new NativeArray(0);
    private int current = 0;

    public void readOutput(JavaScript javaScript) {
        output = (NativeArray) javaScript.valueOf("output");

    public String nextValue() {
        return (String) output.get(current++);

Finally, this is the class that hides the fact that scripts are mixed within html.

public class XomJavaScriptSource implements JavaScriptSource {

    private final Document document;

    public XomJavaScriptSource(String htmlPage) {
        document = parsePage(htmlPage);

    public void evaluateWith(JavaScript javaScript) {
        Nodes scriptNodes = document.query("//script");
        for (int i = 0; i < scriptNodes.size(); i++) {
            evaluateNode(scriptNodes.get(i), javaScript);

    private final Document parsePage(String htmlPage) {
        try {
            return new Builder().build(htmlPage, null);
        } catch (Exception e) {
            throw new RuntimeException(e);

    private void evaluateNode(Node scriptNode, JavaScript javaScript) {
        if (scriptNode instanceof Element) {
            Attribute sourceAttribute = ((Element) scriptNode).getAttribute("src");
            if (sourceAttribute != null) {

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s