DEV Community

Jesse Warden
Jesse Warden

Posted on • Originally published at jessewarden.com

How Do You Change UI Design When Testing it is Hard?

TDD in non-UI: “Man, this code requires a lot of stubs just to make 1 function call. This API design is bad, I should fix it”.

TDD in UI: “Man, this code requires a lot of stubs, I should fix. Hey Visual Designer, can you… no? Ok. Hey API designer… can you? No… ok.”

This is one reason of many why UI developers like back-end for front-ends. When testing your UI, having to stub 20 http requests + 2 JWT tokens just to show 1 screen is painful. Having just 1 or 3 API’s for a screen is so much easier, and makes your tests less likely to break in the future.

However, while testing can reveal a bad API for your UI, there isn’t much you can do to change the visual UI itself. In my years of doing UI, I’ve had 1 designer slightly change an interaction model because of the difficulty of testing it. (Read: highly unlikely to happen).

If the screen requires lots of data, and has lots of interactions… well it requires it. At that point, your only saving grace is finding ways to re-use your stubs without creating a mess in your tests.

https://samnewman.io/patterns/architectural/bff/

Top comments (6)

Collapse
 
ravavyr profile image
Ravavyr

I don't quite understand your point here.
Changing an interface is easy. Restyling something, adding padding, margins, changing font sizes, colors, background colors, borders. All of that is super easy if you encounter a user interface problem. [In web dev anyway]

Can you elaborate on why you find it to be such a problem?

Collapse
 
jesterxl profile image
Jesse Warden • Edited

tl;dr; As your UI grow's, if you are not also building your own API's, you're stuck with how the back-end works. This can mean many HTTP calls are required to show 1 screen, which in turn makes your tests have many cy.intercept calls, many different fixtures, and in turn makes the tests a lot harder to main tain and brittle.

You mentioned "changing" things on UI is easy. If it is, I then ask...

How do you test first and How do you know you didn't break something?

We utilize unit and functional tests for this. For the functional tests, we're utilizing Cypress. To stub HTTP calls the UI makes, we're utilizing cy.intercept. Some UI's require many HTTP calls to show 1 screen.

If I'm drawing a table with a filter, that may be a simple POST call. I can stub that with 1 cy.intercept call:

// psuedo code
cy.intercept('/api/getData', somefixture.json)
Enter fullscreen mode Exit fullscreen mode

However, as the UI grows, and what the user can do grows, so too do your HTTP calls. If you're the UI developer and you are also building your API's to support the UI, then you typically first think "How does the user get here, and what data do I need to give the UI to show this screen?"

For the above, you might say "Ok, a single table with a text field to filter a search, then perhaps later a way to paginate. Let me setup a POST call to filter the search, and I'll return 10 rows as a JSON Array".

Later, the designer creates an additional grid below the table as a shortcut to the user. Now you have 2 HTTP calls for the same page. If you're building your own API's, you'll say "I'll just piggy back that data for the bottom screen on the same API since it's possibly filtered by the search above, and it's 1 additional database call I can easily cache since it's from the same table". So you can update your fixture to cy.intercept, and update your Cypress test to have an additional assertion about the data on the page.

This isn't often the norm, though. A lot of UI developers I've met are not building their own API's. They're either consuming "Whatever the back-end devs give us". In the scenario above, they now have 2 API calls to show 1 screen. So they'll add a new cy.intercept with a new fixture.

2 is not a big deal; just shove in your beforeEach, and assuming the API design has died down, you probably don't have to edit those, nor the fixtures much.

However, as time goes on, the UI can diverge form what the API's provide. Eventually you'll be making many API calls, either to support multiple pieces of data, or sometimes to just orchestrate data you need from many places. Both result in many additional cy.intercepts (e.g. stubs) just to make a simple assertion. In a UI with many interactive screens making many ajax calls, acceptance testing can become quite tiring and fragile.

I acknowledge there are degree's here. Lots of text content, and only a few forms like cnn.com for example; while a lot of data, the screens are pretty static and not interactive so they don't change. With something like Figma, Trello, or many interactive forms on a "page", that'd be the opposite end of the extreme.

Ultimately even if the UI Designer does not know about API's and what data is available, the UI Developer does, and it's best when that UI Developer can make their own API's to simply how many Ajax calls the UI is making, therefore making it much easier to acceptance test their UI and to maintain those tests in the longer term.

Collapse
 
ravavyr profile image
Ravavyr

You're overcomplicating it and i think it's because you're working in an environment where the left hand [UI designers] does not know what the right hand [backend developers] are doing

That page you described with tables pulling from an api. I've written dozens if not hundreds of pages like that and i just build the UI myself and call the API myself and in many cases build/design the database and data structure for the API as well as the interfaces [though i rely on predesigned UI components i can reuse most of the time]

How do i test it?
I run the page, i put in fake or real data if i have it and load the page, interact with it, use it.

This really is nowhere as complicated as you make it sound

Thread Thread
 
jesterxl profile image
Jesse Warden

Are you writing automated tests?

Thread Thread
 
ravavyr profile image
Ravavyr

nopes, i mean, i do, for some things, but it's rare.
Instead i put validation code into things and log my errors and send alerts for issues like that.
Now i can see for UI/UX stuff, automated testing relies in the interface, so it's "another thing to update" when you make changes, but i still don't think it's so complicated as you described.

Now, i see you have 20 years exp, so i think the system you described is a corporate system where these tests are bread and butter and it's super important these tests can run smoothly and have to be in sync with every change made so you have so many steps in your process.

I build websites. The vast majority of them have zero tests. They have backups in case things go to shit with the host/server, and some send notifications based on some tools I use. They don't get the kind of traffic where a minor UI bug is gonna cost them a million bucks a day. For those clients we use other more complicated setups too, but i've yet to see one project where automated testing was highly important and wasn't just forgotten later on anyway, or it was so integrated that it never worked properly because the systems were being updated/changed so frequently [which probably goes back to your original point of it potentially being a complicated problem]

Thread Thread
 
jesterxl profile image
Jesse Warden • Edited

Those of us doing Continuous Integration Continuous Delivery are writing automated tests, usually first, for both UI's and API's. If you want to ensure the code is easy to change later with things not breaking and causing regression bugs, you'll want a suite of automated tests.

For content heavy sites, totally agree. I don't have tests for my blog, for my posts here, for the books I wrote, and any documentation (... although, I wonder if there is linting for spelling).

Yeah, I know it seems counter-intuitive; why write tests when the code is changing so much, so frequently? But that's the whole point of doing the tests first. Many of the benefits include:

  • only writing what you need to make the basic test pass; if the designer changes something, or if you learn something new from the user, you didn't spend a lot of time gold-plating the code
  • if things seem on track, then you can gold plate the code while ensuring you don't break anything (e.g. refactoring)
  • when you start having multiple features in an app, and you're adding a new feature and changing it multiple times a day, you can ensure you aren't breaking the other features you wrote

I've had a similiar experience as you; many places do not do automated testing; they take quality assurance away from the developers and create another team for it. There's also a lot in the testing world that can make automation harder (mocks, slow builds, etc) so even those who try are met with a lot of challenges.