Skip to content

A largely BDD version of the "official" Angular "phone store" tutorial

License

Notifications You must be signed in to change notification settings

UMM-CSci-3601/revised-angular-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Tests

A BDD version of the "Phone Store" Angular tutorial

This is a version of the "official" Angular "Phone Store" tutorial generated by @kklamberty and @NicMcPhee using a largely BDD (behavior-driven-development) approach. We're essentially starting with E2E (end-to-end) tests and using those to drive the development of components, services, features, etc.

Our reason for this is that most of the commonly used examples, such as the phone store tutorial and the Tour of Heroes tutorial, have no testing. This (sort of) makes sense from the standpoint of the Angular developers their goal is to teach Angular, not cover Karma and Jasmine and Protractor, etc. It's frustrating when one of the selling points of Angular is that it's a readily testable framework, though, but none of the major examples actually include testing.

Thus we hope that by documenting an example of how one could build the phone store tutorial in a largely BDD style we can provide:

  • An example of using BDD to document, test, and drive the implementation of complex functionality
  • Reasonable examples of writing E2E tests
  • Reasonable examples of writing unit tests
  • Suggestions for where to use E2E tests, and where to use unit tests

We will not repeat all the tutorial material and explanations in the phone store tutorial, so if you're new to Angular it would probably be useful to either go through that first, or at least be reading along through it while you're working through this tutorial. Based on our experience with students, however, there are some things (beyond testing) we will try to highlight or expand on, including:

  • Observables and RxJS (& asynchrony in general)
  • Parent/child component relationships

We might also provide a version of this that has all the E2E tests but none of the implementation code for those that would like to completely build the tutorial in a BDD fashion, but without having to write the tests first.

We will also not provide a complete tutorial on E2E tests with protractor or unit tests with karma, or on using jasmine to write tests. We will explain some of these ideas as we go, but you should hit up the Internet for a more complete introductions to those tools.

Setting up the Angular client

Create the Angular project

  • ng new phone-store
    • ❓ This creates a directory called phone-store in the project. Do we want to change the name to client to be more like our later structures?
    • At this point you can go into the phone-store directory and run ng server and see our little project! 😄 It of course doesn't actually do anything interesting yet, but it does work.

Setup GitHub Actions

@floogulinc set up the GitHub Actions based on work done in S20. These are all laid out in this pull request.

For reasons we don't fully understand, this requires installing some webdriver-manager binaries that didn't get installed on their own. Without them, we can't run the e2e tests.

Running:

node_modules/protractor/bin/webdriver-manager update

installed the necessary binaries and all the tests ran and passed.

Start making components

The tutorial starts you off with two components:

  • top-bar, which has the app title and a checkout button
  • product-list, which lists the products available at the store

and essentially no implemented "logic" except for the fact that the title links to the route '/'.

A question is what we can/should test about these components. The top-bar component, for example, has several properties that could be tested:

  • It has a certain height.
  • It has a certain background color (a blue).
  • It contains an h1 element with the string "My Store". This text is white against the blue background. This is a link; clicking it takes you to the '/' route, which at the moment is just the same page. (So it doesn't really seem to do anything at the moment, but will clearly serve a purpose when there is a second page and beyond.)
  • It contains a checkout button containing both a shopping cart icon and the string "Checkout". The button is white, and the text and icon are blue.

Many of these are really display properties (e.g., colors, sizes, layout) and probably shouldn't be captured in tests. We probably don't want an E2E test that checks that the shade of blue in the top-bar is "just so"; that would be really annoying if a design team came in and wanted to provided several possible color themes for consideration. It might also break the test if the user was using "dark mode" instead of "light mode", or the functionality was added later that let the user specify things like colors.

Things like the title (currently "My Store") are more complex. The fact that "My Store" is clearly not a good title is a sign that we might want to have tests that capture that exact text. Early in a project the team may not have settled on a title yet, and embedding it in the tests might prematurely "lock in" a title that no one is actually terribly fond of. So instead of testing for a specific title string, at the beginning maybe it would be sufficient to confirm that there is an app-top-bar element, and that it contains an h1 element, without worrying about the text in that element.

Create the top-bar component

We created an E2E spec that required (indirectly through the page objects) the existence of an app-top-bar component. (ce1e3db) We then satisfied that spec by generating the component (35ff8b2):

  • ng generation component top-bar

and replacing the entire contents of app.component.html with the HTML from the tutorial, which includes adding:

<app-top-bar></app-top-bar>

at the top. (594c6d1)

We then added an E2E spec that required that there be a checkout button, and got that to pass by pasting in the button code from the tutorial. (9421cb8)

At this point the top bar is complete except for the fact that "My Store" should be a link to '/'. So we added an E2E spec that clicked on the title and checked that we were on the "home page". (9f3046d) This is a slightly awkward test at the moment because everything is on the home page; we should probably extend it when there are additional pages to make sure the link brings us back home from those pages.

The tests all passed, but we realized that there was no styling, so we copied over the CSS from the tutorial and pasted it into our project. We also needed to link to the Material Icons font in index.html to bring in the shopping cart icon used in the checkout button.

This completes the top bar for now.

Create a product-list component

We added a spec that required an app-product-list element. This failed.

We then generated the component:

  • ng generate component product-list

As well as creating the component, we also need to route the default path to the product-list component. This requires adding this bit of code to app.module.ts:

    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
    ])

We just copied in the app/products.ts file that has the list of phones, descriptions, and prices.

We added a spec that required an h2 header in the app-product-list element, and added code to product-list-html so that would pass.

We specified that there should be three h3 elements in the app-product-list element. We got that to pass by adding the products field to the ProductListComponent and with an *ngFor in the product list HTML.

Checking in on the unit tests

We'd been focused entirely on the E2E tests so far, and it occurred to us that we should check on the unit tests. Running

ng test --code-coverage --watch=false

ran the unit tests for us. We had 100% coverage at this point, largely because we have pretty much zero logic. 😄 One test did fail, however, because we no longer display the default text

phone-store app is running!

We changed it to extract the title from the top bar and confirm that it contains "store" (with upper or lower case 's') with:

    expect(compiled.querySelector('app-top-bar h1').textContent)
        .toMatch(".*[sS]tore.*");

This failed, though, because the test didn't know how to understand the app-top-bar HTML element from the top-bar component. Adding TopBarComponent to the declarations section in app.component-spec.ts fixed that problem. Now the tests pass and our coverage is still at 100% (because there's no meaningful logic).

⚠️ There was still the following warning:

WARN: 'Can't bind to 'routerLink' since it isn't a known property of 'a'.'

Nic spent way too long flailing around on that (searching the Internet wasn't a ton of help) until he finally thought to set --watch=true and look at the browser console. That pointed out that the problem was in top-bar.component.spec.ts, which wasn't where he had been looking at all. Once he was looking in the right place, he realized that the problem was that we weren't importing RouterTestingModule; adding that fixed the problem right away.

Fleshing out the product list

So far all the product list is is a list of product names. The first section of the tutorial expands that to display various pieces of information (e.g., description) formatted in various ways. It also makes each product name a link, which will ultimately (in the second section of the tutorial) link to a separate, more detailed, page for that product.

The first thing the tutorial does is make each product name a link. These links have no href so they don't go anywhere yet. They do, however, all have titles that have the form

"product.name + ' details'"

i.e., the name of the product followed by the word "details".

We then added E2E tests that required that:

  • Each product name is a link
  • Each link has a title attribute that ends in ' details'

Those tests failed, and we then added the code from the tutorial that got them to pass.

We also refactored all the page.navigateTo() calls up in the the beforeEach section so we weren't repeating them a zillion times.

About

A largely BDD version of the "official" Angular "phone store" tutorial

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •