There are several good sites that go into detail about testing Ionic
and Ionic 2 apps, e.g.,
this site. Unfortunately, they require many installation steps
and editing of configuration and JavaScript files. I've encountered
fatal typos, especially in specifying subdirectories,
and out-of-date library names, e.g., angular-cli instead of
@angular/cli. Several reporting tools have changed
names.

For now, the simplest starting point is
this Github starter project.
There are many more things you could add, as described
on other Ionic and Angular testing sites.
This will give you a working test set up.
Then you can add the rest.

The Ionic developers have said that eventually
the testing framework will be included in Ionic and this
repository will be unnecessary. We'll see.

Run the unit tests

If everything installed, now run the unit tests
with the following command:

npm test

The Chrome browser should open
a new window showing the Karma home page. Click on
the Debug button to see a report on the test
results. It should say 4 tests were run, with 0 failures.

The default test script keeps running. Stop it
with a command-C or control-C. Normally you would leave it running until
there no failing tests. The script watches for code file changes and
reruns the tests within a few seconds of any saved change.
Reload the Debug page to see the new results, when tests finish.

Run the end-to-end tests

To run the end-to-end tests, you have to start the app first:

ionic serve

Assuming it starts without error, open a new command shell,
cd to the project root, and run

npm run e2e

The results of the end-to-end tests are given in the console.
There's just one end-to-end test in the demo. See
end-to-end tests below.

Common Errors and Fixes

Update!

If any errors occur, the first thing to do it make sure you have
an up-to-date NodeJS and up-to-date packages. Run

Add app component test

Copy the file src/app/app.component.spec.ts from
the article. Most of the boilerplate can stay. Two things need to change.

The name of the app class is not MyApp.

There is no pages member in the app class,
so expect(component.pages.length).toBe(2) will not compile.

Open src/app/app.component.ts. There'll you find
the name of the app to use in the test. You'll also see that
the app class has a rootPage member. Change
the test for 2 pages to be a test that the root page is
the Posts page.

Save the changes. The tests should re-run automatically,
if you have not force-quit the test script.

Test Files

Most of the time, what you need to do is create test files.
There are two kinds: unit tests, for testing components,
and end-to-end tests, for testing the app, i.e., integration testing.

Unit Tests

Unit tests by definition test some unit of code, e.g., a function
or a class, not an entire system. Unit tests should run very fast
and not depend on external modules, the network, a database, etc.

The demo project includes two examples of unit tests. Both
are testing Angular components. That means they are testing objects
that normally are created and interacting inside an Angular app.
To test these as independent units, the rest of the app
has to be "mocked". The library for doing that
is TestBed.

The recommended practice in Angular is to create a separate
unit test file for every component you want to test, rather than
one big test file. The file is placed
next to the component, for convenience. The file name is
the same as the component, but ending in .spec.ts.

Because this is such a simple app, there are only two unit tests.
One is for the component representing the app itself,
app.component.ts. Next to it is the test file,
app.component.spec.ts

The other unit test is for one of the two HTML pages in the app.
While it's easy to write code to look at HTML and test for
certain properties, this quickly leads to fragile hard to read tests that
break with minor changes in the user interface.

To avoid that problem, best practice is to create page objects.
These are JavaScript objects that provide controlled access to the parts
of a web page. The object takes care of the specific details of the page.
If the page changes, the object may need to change. But all the testing
is done using the page object's public functions, and this rarely
changes.

The demo project has an example of a page object and the test for that
object:

page1.ts is the page object. Objects are usually
more complex but this just connects the object to the appropriate URL.

page1.spec.ts is the test for the
page object. Most of this is boilerplate. Just the last few lines
are the real test, which use the regular expression /ionic/i
to see if the page mentions Ionic.

End-to-end Tests

End-to-end tests test the actual app, using Protractor and Selenium
to communicate with a running web version of the app.

Because the tests are not component-specific, the tests are stored
together in the directory e2e, and no mocking is done.

The example project has one end-to-end test,
app.e2e-spec.ts, that just checks to see if
opening the app displays a page that appears to have the right content.
As with the page component unit test, it uses a page object,
app.po.ts
to insulate the test from small changes in the web page.

A test like this serves as a good "is it up?" test that you run
to make sure you haven't completely broken the app with some change.