Skip to content

Commit 88df212

Browse files
committed
Add the "Decouple the back-end and front-end test through Contract Testing" chapter
1 parent 6e341d3 commit 88df212

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
6. [Tools (2)](#6-tools)
3333
7. [Component Testing (3)](#7-component-testing)
3434
8. [Advanced (5)](#8-advanced)
35-
9. [Real Life Examples (2)](#9-real-life-examples)
35+
9. [Real Life Examples (3)](#9-real-life-examples)
3636

3737
<br/><br/>
3838

@@ -326,6 +326,16 @@ If a test cannot produce reliable results, it reduces confidence in the tests an
326326

327327
🔗 [**Read More: From unreadable React Component Tests to simple, stupid ones**](./sections/real-life-examples/from-unreadable-react-component-tests-to-simple-ones.md)
328328

329+
<br/>
330+
331+
## ![] 9.3 Hasura - Decouple the back-end and front-end test through Contract Testing
332+
333+
**TL;DR:** E2E tests do not scale well for hig applications, with thousands of user flows. Things get even worse if the UI E2E tests are used to test the server too because the result is hundred of slow and coupled tests. In Hasura, an internal working group proposed to decouple the back-end and front-end tests.
334+
335+
**Otherwise:** The test suite grows to hundreds and hundreds of (slightly brittle, by nature) tests becoming a serious bottleneck for the release pipeline.
336+
337+
🔗 [**Read More: Decouple the back-end and front-end test through Contract Testing**](./sections/real-life-examples/hasura-contract-tests.md)
338+
329339
<br/> <br/>
330340

331341
## Steering Committee
282 KB
Loading
514 KB
Loading
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Decouple the back-end and front-end test through Contract Testing
2+
3+
<br/><br/>
4+
5+
### One Paragraph Explainer
6+
7+
E2E tests do not scale well for hig applications, with thousands of user flows. Things get even worse if the UI E2E tests are used to test the server too because the result is hundred of slow and coupled tests. In Hasura, an internal working group proposed to decouple the back-end and front-end tests.
8+
9+
<br/><br/>
10+
11+
## Context
12+
13+
I (a Front-end engineer, keep it in mind) recently championed an initiative aimed at reducing Hasura's CI pipeline duration and the dependence on not-scaling-well E2E tests.
14+
15+
The problem is that **the Server team defensively uses the Hasura Console's** (the main UI of the company) **E2E tests** to check for regressions. If the Console works as expected, the Server works as expected as a by-product.
16+
The CI pipelines must build both the Server and the Console and then launch the Console's E2E tests. This happens for every PR, both the Server-related ones and the Console-related ones.
17+
18+
![A graph showing the process of building both the parts of the system to test them](/assets/images/hasura-contract-tests/coupled-tests.png)
19+
20+
Why is it a problem? Because the Console takes 10 minutes to build and 15 minutes to run the tests (spread across eight processes at the moment). Waiting **25 minutes to ensure that a bunch of Server endpoints correctly does not scale**.
21+
22+
How can we reduce this problem?
23+
1. By relying on more low-level tests on the Server side
24+
2. By using a series of requests performed against the Server, waiting for some exact responses. The series of requests and responses made the "contract" between the Console and the Server. Testing this contract would partially replace the E2E tests.
25+
26+
![A graph showing the both the parts of the system tested individually](/assets/images/hasura-contract-tests/decoupled-tests.png)
27+
28+
29+
You can find all the info/answers I shared internally below. Please note that the questions below refer to the ones everyone has to answer before proposing a topic to the internal Architectural Working Group.
30+
31+
---
32+
33+
## Step 1: the proposal to the Architectural Working Group
34+
35+
Questions that [foster dialogue](https://www.kitchensoap.com/2017/03/06/book-suggestion-dialogue-the-art-of-thinking-together/)
36+
37+
_What problem are you solving?_
38+
1. **Reducing the number of E2E tests** by introducing Integration tests for the Console
39+
2. **Speeding up the CI** pipelines by leveraging faster tests
40+
3. Avoiding the Server requiring to build the Console and launching its tests to know if an API works or not
41+
4. Avoiding the Console devs to have the Server working locally or in the cloud
42+
5. Detecting regressions upfront and allowing to notice what is the component of the equation that introduced the regression (the frontend or the backend)
43+
44+
_Why are you solving this problem?_
45+
1. Because **relying on E2E tests does not scale**. Backend and frontend could have slightly different testing pyramids/trophies, but in both cases, E2E tests always stay at the top: high confidence at the cost of flaky and extremely slow tests
46+
2. Because **the feedback loop is too long**, building the Console + launching its tests take at least 25 minutes (thanks to CI parallelization, otherwise it's even worse)
47+
48+
_Is it possible I don't even have to solve this problem?_
49+
1. No. Regressions on the Server cannot be found out after a 30-min CI
50+
2. No (2), because the Console's UI is not fully covered in terms of E2E tests and will never be. Otherwise, we end up having 5-hours CIs, not 30-mins ones
51+
3. Wait... Wasn't you, Stefano, fixing the Console's E2E tests? Why do you want to get rid of them? Because "fixing" means the following points, but they do not resolve the root cause of the problem of using E2E tests
52+
- Removing the source of flakiness entirely but it's not quite possible because of the large number subjects involved (FE+BE+DB)
53+
- Speeding up the tests, but we cannot expect more than a 30%-50% improvement
54+
- Making them helpful in case of failures
55+
4. The Console will be migrated to [Nx](https://nx.dev/), and in the future, the result of E2E tests will be cached, why caring about their slowness? Because Nx caches the E2E tests based on the parts of the UI that change. If the server change, Nx cannot detect it, and they won't run the E2E tests, resulting in server-related regressions going directly to production
56+
57+
_How would you solve your immediate problem without adding anything new?_
58+
By removing some E2E tests and writing Console's tests against static fixtures. As a result, the Server loses confidence because it's coupled with the Console's E2E tests.
59+
60+
_Write what it is about the current stack that makes solving the problem prohibitively expensive and difficult._
61+
Checking for server API regressions means building the Console (10 minutes), launching the Console's E2E tests (15 minutes, thanks to CI parallelization), and we have only ~200 E2E tests out of the thousands of things the users can do with the Console.
62+
63+
_What are other potential solutions for the problem?_
64+
The server APIs could also be tested in isolation, but… I imagine that the problem here is the application state. The Console's E2E tests are convenient from this point of view because usually they
65+
- Create the entity
66+
- Modify the entity
67+
- Delete the entity
68+
Hence the "modify the entity" API is called after the "create the entity" one, creating the application state needed for the former API to work.
69+
At the same time, I think that a proper testing suite could reduce the need for this "APIs called from an external component against a working server" but this is out of my frontend-only experience.
70+
71+
_How can you build confidence in a specific solution approach?_
72+
Confidence comes from the fact that we would test the same things as before, but in a different way
73+
74+
_What is the CON of the approach?_
75+
The Contracts and the static fixtures must be kept updated. The Contracts will be generated manually, while the static fixtures used by the UI should be typed
76+
77+
_What are the tradeoffs and consequences of the solution?_ (answer by one of the Server folks)
78+
- Currently, the Server gets a lot of release confidence from the console E2E tests. Implementing this strategy would mean more work by the server team to preserve that level of confidence.
79+
- The majority of coverage for the backend currently centres around consumption of the GQL API ("if I send this GQL, I get this JSON/YAML") - a similar approach would work for the console APIs ("if I send this JSON to HGE, I expect to receive this JSON"), but this would require some upfront work.
80+
- There could be a drift between the actual server behaviour and the behaviour stated by the mocks. This can be mitigated in a number of ways, though.
81+
- Potentially, the space between FE/BE engineers will grow further, though vertical team structures should help a lot here.
82+
All in all, the migration away from E2E tests for the Console would require a reasonable amount of test suite effort for BE teams. However, the benefit will most likely be a substantial improvement in CI times, and there's no reason we can't, say, treat the console team mocks as integration tests for the API.
83+
84+
## Step 2: the implementation of the automatic recorder
85+
86+
You can find the code [here](https://github.com/hasura/graphql-engine/blob/576417408709b1f9eb981a2fd3106ef523955aee/console/cypress/support/contractIntercept/contractIntercept.ts).
87+
88+
## Step 3: Closing thoughts
89+
90+
Compared to the initial proposal
91+
1. The contract is not automatically recorded. The developer must adapt the E2E test following [this guide](https://github.com/hasura/graphql-engine/blob/576417408709b1f9eb981a2fd3106ef523955aee/console/src/docs/dev/testing/6-export-contract-from-e2e-test.stories.mdx) to record the contract
92+
2. I’m going to remove the E2E tests that are almost duplicates (ex. creating a query action or a mutation does not differ, I’ll remove one of them)
93+
3. For other E2E tests, I’ll share the contract before contextually
94+
4. All the features that rely on the Console directly running SQL queries will rely on E2E tests, but only for the happy path
95+
5. The frontenders won’t be able to automatically export the contract and use it for integration testing (read [here](https://stackoverflow.com/questions/68455650/cannot-make-cypress-and-pact-work-together/68492932#68492932) and [here](https://pactflow.io/blog/a-disastrous-tale-of-ui-testing-with-pact/)). Anyway, this is not a big problem because it’s strictly related to migrating the E2E tests to integration ones. When we are creating new features, the integration tests are smaller (that also means less requests), and we should have the typed mocks from the Storybook stories of the involved components that could also be imported in the Cypress tests.
96+
6. The exported JSONs do not leverage [the power of Pact](https://github.com/pact-foundation/pact-specification/tree/version-3) (ex. cannot include special operators that allow for instance “to test that the id sent in the 3rd response is the same as the one sent in the 5th response”)
97+
98+
<br/><br/>
99+
100+
*Crossposted by [NoriSte](https://github.com/NoriSte) on [dev.to](https://dev.to/noriste/decouple-the-back-end-and-front-end-test-through-contract-testing-112k).*

0 commit comments

Comments
 (0)