4

I'm new to TypeScript, but experienced in C#. I'm trying to do something very simple, and I'm missing something fundamental. I'm using Protractor to write User Tests on an Angular front-end. I'm using the Page Object pattern, and I want to keep the Page Object in a separate file from my user tests so I can share the Page Object among several user test files.

I keep getting an error saying the page object class is not a function when I try to new up the class. What am I doing wrong? Here's my code that is failing with the error:

TypeError: UserTests.DashboardPage is not a function.

Page Object File: named dashboard.pageobject.ts

module UserTests {
    export class DashboardPage {
        setupPage = function () {
            console.log("setupPage function");
        };
    }
}

Protractor Test File: name dashboard.test1.spec.ts

/// <reference path="../../../typings/jasmine.d.ts" />
/// <reference path="../../../typings/angular-protractor.d.ts" />
/// <reference path="../../../typings/selenium-webdriver.d.ts" />
/// <reference path="dashboard.pageobject.ts" />

module UserTests {
    describe('When testing the Dashboard page', function() {
        it('Should pass', function () {
            var page = new UserTests.DashboardPage();
        });
    });
}

The error occurs on the line: var page = new UserTests.DashboardPage();

UPDATE (11/17/15):

I finally put all the pieces together after reading basarat's reply about internal modules. I removed the module keyword from the page object file, made the method setupPage public, and added an import statement in the spec file. Reading about external modules made me realize Node considers each file a module already. This post (also by basarat) drove the point home for me to make the function public. Also, I installed RequireJS. Here's my final code.

Page Object File:

export class DashboardPage {
    public setupPage = function () {
        console.log("setupPage function");
    };
}

Protractor Test File:

/// <reference path="../../../typings/jasmine.d.ts" />
/// <reference path="../../../typings/angular-protractor.d.ts" />
/// <reference path="../../../typings/selenium-webdriver.d.ts" />

import pageObj = require("./dashboard.pageobject");

describe('When testing the Dashboard page', function() {
    it('Should pass', function () {
        var page = new pageObj.DashboardPage();
        page.setupPage();
        console.log('I made it!');
    });
});

My thanks goes out to the people who responded!!

Community
  • 1
  • 1
Chris V
  • 83
  • 6
  • I don't know how the code snippet thing works, but are you compiling your TypeScript to Javascript before loading it? I see `module` and `export` in your code. – amg-argh Nov 16 '15 at 23:04

2 Answers2

2

Any help is greatly appreciated! Thanks!

You are using internal modules (aka namespaces). This means that you need to load the files in the right order or concatenate in the right order. That is what is going wrong here.

More on this : https://github.com/TypeStrong/atom-typescript/blob/master/docs/out.md

basarat
  • 261,912
  • 58
  • 460
  • 511
  • Thank you for the reply. I agree that the dependency between the 2 files is not getting resolved. Since I'm using Protractor, I'm struggling with how to resolve the dependency. I've been reading about RequireJS, but I have not seen a good example of how to get it to work in the context of Protractor (rather than a web page). Since Protractor is running under Node, I need to figure out how to get RequireJS to work with Node on the server without an HTML page. I'm still researching. – Chris V Nov 17 '15 at 19:05
2

According to this GitHub issue, Typescript support is in the Protractor's Upcoming milestone. So in the meanwhile you can compile your Typescript code to JavaScript before running the test.

Steps would be the following:

  1. Compile specs file dashboard.test1.spec.ts with --outFile:

    tsc dashboard.test1.spec.ts --outFile dashboard.test1.spec.out.js
    
  2. Use newly created dashboard.test1.spec.out.js file in your Protractor configuration file.

Of course, instead of dashboard.test1.spec.out.js you can use any name that you find convenient (but you must specify an output name).

Two clarifications:

  • When you use --outFile option, the compiler will recursively follow all reference tags (/// <reference path="file-name.ts" />) and then output the compiled JavaScript for all referenced Typescript files to a single file (the deepest references will be on top).
  • You can use --out instead of --outFile. --out is deprecated in favor of --outFile (see Typescript compiler options), but both should work just fine.
Nikola Prokopić
  • 3,246
  • 3
  • 17
  • 20
  • This seems fragile. Also, if I use this technique, then I still don't understand how to resolve the dependency between the 2 files since there is no HTML file to put script tags in. Protractor runs on the server under Node, and I don't know where to place the 2 files so that they combine into a single executable (and are resolved with each other). – Chris V Nov 17 '15 at 19:13