I have a screencast on developing a front-end JavaScript app that covers this topic. [1] The short answer is that you approach it in the same way you approach other TDD challenges: think about the code you want to write, then write a test that fails until that code has been written, then improve it, then repeat. A good test will talk more about the observable behavior of the unit rather than the way it's implemented.
So if your production JavaScript code sets a class based on some piece of business logic, your test checks that it sets that class in that situation. That may mean doing some DOM element creation in your test setup.
Testing HTML and CSS is a bit trickier. I'm developing a tool called Quixote [2] that enables TDD of this sort of code. It lets you do things like say "the login button needs to be 20px to the right of the nav bar." Same deal: you think about what you want your CSS to do, write the test, then write the CSS, then improve it.
Regardless, these are unit tests (or unit-like tests; I don't want to argue semantics), not end-to-end tests. Each one is focused on testing a specific thing, stay inside the browser process, and you use them to drive development. The key is to use good tools; I like Karma [3] because it allows me to run my tests against multiple browsers simultaneously, including mobile devices.
And, with apologies to @Anchor, you should absolutely test using real browsers. There are meaningful differences between browsers and you want your tests to catch those differences. Speed is not a problem if you use good test design and tooling; my Quixote tests use Karma, run against ten browsers, and execute 200 tests / sec.
So if your production JavaScript code sets a class based on some piece of business logic, your test checks that it sets that class in that situation. That may mean doing some DOM element creation in your test setup.
Testing HTML and CSS is a bit trickier. I'm developing a tool called Quixote [2] that enables TDD of this sort of code. It lets you do things like say "the login button needs to be 20px to the right of the nav bar." Same deal: you think about what you want your CSS to do, write the test, then write the CSS, then improve it.
Regardless, these are unit tests (or unit-like tests; I don't want to argue semantics), not end-to-end tests. Each one is focused on testing a specific thing, stay inside the browser process, and you use them to drive development. The key is to use good tools; I like Karma [3] because it allows me to run my tests against multiple browsers simultaneously, including mobile devices.
And, with apologies to @Anchor, you should absolutely test using real browsers. There are meaningful differences between browsers and you want your tests to catch those differences. Speed is not a problem if you use good test design and tooling; my Quixote tests use Karma, run against ten browsers, and execute 200 tests / sec.
[1] http://www.letscodejavascript.com
[2] https://github.com/jamesshore/quixote
[3] http://karma-runner.github.io/0.12/index.html