Skip to content

Commit 11e25bb

Browse files
Full run e2e on every branch (#36)
* Full run e2e on every branch * Fix incorrect caveat config * refactor(e2e): remove build step from CI and improve dependency polling logic, remove explicit turbo cache dir * Add timeout, to fail after dependencies are not available before 5 minutes. Fix issue where dependency is marked as unavailable even when it's responding, if the method is not supported. * Conditionally log service availability to prevent misleading logging (#40) Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: jeff.smale <jeff.smale@consensys.net> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: jeff.smale <jeff.smale@consensys.net>
1 parent a3f4b48 commit 11e25bb

10 files changed

Lines changed: 53 additions & 76 deletions

File tree

.github/workflows/build-lint-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
uses: MetaMask/action-checkout-and-setup@v1
2727
with:
2828
is-high-risk-environment: false
29-
cache-node-modules: ${{ matrix.node-version == '22.x' }}
29+
cache-node-modules: true
3030
submodules: 'recursive'
3131

3232
- name: Install Foundry

.github/workflows/end-to-end-tests.yml

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,21 @@ on:
1313
NPM_CLIENT:
1414
type: string
1515
default: 'yarn'
16-
RUN_FULL_TESTS:
17-
type: boolean
18-
default: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') }}
1916
workflow_dispatch:
20-
inputs:
21-
RUN_FULL_TESTS:
22-
type: boolean
23-
default: true
2417

2518
jobs:
2619
pipeline:
2720
name: Turbo Pipeline
2821
runs-on: ubuntu-latest
2922
strategy:
3023
matrix:
31-
node-version: [18.x, 20.x]
24+
node-version: [18.x, 20.x, 22.x]
3225
steps:
3326
- name: Checkout and setup environment
3427
uses: MetaMask/action-checkout-and-setup@v1
3528
with:
3629
is-high-risk-environment: false
37-
cache-node-modules: ${{ matrix.node-version == '22.x' }}
30+
cache-node-modules: true
3831
submodules: 'recursive'
3932

4033
- name: Install Foundry
@@ -54,15 +47,5 @@ jobs:
5447
- name: Install Yarn dependencies
5548
run: yarn install
5649

57-
- name: Run build
58-
run: yarn build
59-
env:
60-
NODE_ENV: production
61-
6250
- name: Run end-to-end tests
63-
run: |
64-
if [[ "${{ inputs.RUN_FULL_TESTS }}" == "true" ]]; then
65-
yarn e2etest:full
66-
else
67-
yarn e2etest:smoketest
68-
fi
51+
run: yarn test:e2e

.github/workflows/main.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ jobs:
8383
with:
8484
commit-starts-with: 'Release [version],Release v[version],Release/[version],Release/v[version],Release `[version]`'
8585

86-
8786
publish-release:
8887
needs: is-release
8988
if: needs.is-release.outputs.IS_RELEASE == 'true'

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ yarn test
4242
Run the `delegator-e2e` integration test suite:
4343

4444
```sh
45-
yarn e2etest:full
45+
yarn e2etest
4646
```
4747

4848
# Contributing

package.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
],
1414
"scripts": {
1515
"allow-scripts": "echo 'n/a'",
16-
"build": "turbo build --cache-dir=.turbo",
17-
"build:packages": "turbo run build --cache-dir=.turbo --filter='!./packages/delegator-e2e'",
16+
"build": "turbo build",
17+
"build:packages": "turbo run build --filter='!./packages/delegator-e2e'",
1818
"changelog:update": "turbo run changelog:update --filter='!./packages/delegator-e2e'",
1919
"changelog:validate": "turbo run changelog:validate --filter='!./packages/delegator-e2e'",
2020
"clean": "turbo clean",
@@ -23,8 +23,7 @@
2323
"generate:abi": "cd ./shared/abi/scripts && ./generate-abi.sh",
2424
"lint": "turbo lint",
2525
"test": "turbo run test --filter='!./packages/delegator-e2e'",
26-
"e2etest:full": "turbo run e2etest:full --filter='./packages/delegator-e2e'",
27-
"e2etest:smoketest": "turbo run e2etest:smoketest --filter='./packages/delegator-e2e'",
26+
"test:e2e": "turbo run test:e2e --filter='./packages/delegator-e2e'",
2827
"test:watch": "turbo run test:watch"
2928
},
3029
"devDependencies": {

packages/delegator-e2e/README.md

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ When developing end-to-end tests, you can run step 2 repeatedly without having t
2020

2121
### Test Types
2222

23-
There are two types of test suites available:
24-
25-
- **Full Tests** (`yarn e2etest:full`): Runs the complete test suite including all test cases. This is used in the main branch and release branches to ensure comprehensive testing.
26-
- **Smoke Tests** (`yarn e2etest:smoketest`): Runs only the main test cases, skipping edge cases and alternative scenarios. This is used in feature branches for faster feedback during development.
23+
The end-to-end test suite runs the complete test suite including all test cases using `yarn test:e2e`.
2724

2825
## Adding tests
2926

@@ -42,7 +39,7 @@ Some guidelines for creating tests:
4239

4340
### Test Structure
4441

45-
When creating a test file, follow this structure to support both full and smoke test runs:
42+
When creating a test file, follow this structure:
4643

4744
```typescript
4845
import { beforeEach, expect, test } from 'vitest';
@@ -63,12 +60,10 @@ beforeEach(async () => {
6360
- Any important context
6461
*/
6562

66-
// Main test case that will run in both full and smoke tests
67-
test('maincase: Description of the main functionality', async () => {
63+
test('Description of the main functionality', async () => {
6864
...
6965
});
7066

71-
// Additional test cases that will only run in full test suite
7267
test('Description of edge case or alternative scenario', async () => {
7368
...
7469
});
@@ -80,29 +75,15 @@ test('Description of failure case', async () => {
8075

8176
Key points about test structure:
8277

83-
1. **Main Test Case**:
84-
- Prefix the main test case with `maincase:` in the test description
85-
- This test will run in both full and smoke test suites
86-
- Should cover the primary happy path functionality
87-
88-
2. **Additional Test Cases**:
89-
- These will only run in the full test suite
90-
- Can include:
91-
- Edge cases
92-
- Alternative scenarios
93-
- Failure cases
94-
95-
3. **Test Organization**:
78+
1. **Test Organization**:
9679
- Use `beforeEach` for common setup
9780
- Group related assertions together
9881
- Use descriptive test names that explain the scenario
9982
- Include a block comment describing the user story
10083

101-
4. **Common Patterns**:
84+
2. **Common Patterns**:
10285
- Use helper functions from `utils/helpers.ts` for common operations
10386
- Use assertion functions from `utils/assertions.ts` for consistent validation
10487
- Generate unique addresses and keys for each test
10588
- Clean up state in `beforeEach` to ensure test isolation
106-
- `runTest_expectSuccess` and `runTest_expectFailure` to abstract common functionality out of each test within the file
107-
108-
The smoke test runner will only execute tests with `maincase:` in their description, while the full test runner will execute all test cases. This allows for quick feedback during development while maintaining comprehensive testing in the main and release branches.
89+
- `runTest_expectSuccess` and `runTest_expectFailure` to abstract common functionality out of each test within the file

packages/delegator-e2e/package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@
1414
"scripts": {
1515
"build": "cd contracts && forge build && cd ..",
1616
"setup": "yarn build && docker compose up -d && npx tsx src/await-dependencies.ts",
17-
"run-test:full": "npx vitest run",
18-
"run-test:smoketest": "npx vitest run --testNamePattern maincase",
19-
"e2etest:full": "yarn setup && yarn run-test:full; EXIT_CODE=$?; yarn teardown; exit $EXIT_CODE",
20-
"e2etest:smoketest": "yarn setup && yarn run-test:smoketest; EXIT_CODE=$?; yarn teardown; exit $EXIT_CODE",
17+
"test": "npx vitest run",
18+
"test:e2e": "yarn setup && yarn test; EXIT_CODE=$?; yarn teardown; exit $EXIT_CODE",
2119
"teardown": "docker compose down"
2220
},
2321
"peerDependencies": {

packages/delegator-e2e/src/await-dependencies.ts

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import { deployDeleGatorEnvironment } from '@metamask/delegation-toolkit/utils';
1111
import { ENTRYPOINT_ADDRESS_V07 } from 'permissionless';
1212
import { writeFile } from 'fs/promises';
1313

14-
const POLL_INTERVAL_MS = 1000;
14+
const POLL_INTERVAL_MS = 1_000;
15+
// timeout is 5 minutes, which is sufficiently long to never trigger a false positive
16+
const TIMEOUT_MS = 5 * 60_000;
17+
let hasTimedOut = false;
1518

1619
const waitFor = async (name: string, url: string) => {
1720
let isAvailable: boolean | undefined = undefined;
@@ -24,20 +27,21 @@ const waitFor = async (name: string, url: string) => {
2427
});
2528

2629
do {
27-
if (!isAvailable) {
30+
if (isAvailable !== undefined) {
2831
// Only add a delay if it's not the first time
2932
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
3033
}
3134

3235
await client
3336
.request({ method: 'web3_clientVersion' })
3437
.then(() => (isAvailable = true))
35-
.catch((e: any) => {
36-
isAvailable = (e as Error).name !== 'HttpRequestError';
37-
});
38-
} while (!isAvailable);
38+
// as soon as the node is responding (even if it's MethodNotFoundRpcError)
39+
.catch((e) => (isAvailable = (e as Error).name !== 'HttpRequestError'));
40+
} while (!isAvailable && !hasTimedOut);
3941

40-
console.log(`${name} is available`);
42+
if (isAvailable) {
43+
console.log(`${name} is available`);
44+
}
4145
};
4246

4347
const deployEnvironment = async () => {
@@ -61,13 +65,29 @@ const deployEnvironment = async () => {
6165
};
6266

6367
(async () => {
64-
await waitFor('Blockchain node', nodeUrl);
68+
const startTime = Date.now();
6569

66-
const environment = await deployEnvironment();
67-
await writeFile('./.gator-env.json', JSON.stringify(environment, null, 2));
70+
const timeoutRef = setTimeout(() => (hasTimedOut = true), TIMEOUT_MS);
6871

69-
await Promise.all([
72+
await waitFor('Blockchain node', nodeUrl);
73+
74+
const waitingForDependencies = Promise.all([
7075
waitFor('Bundler', bundlerUrl),
7176
waitFor('Mock paymaster', paymasterUrl),
7277
]);
78+
79+
const environment = await deployEnvironment();
80+
await writeFile('./.gator-env.json', JSON.stringify(environment, null, 2));
81+
82+
await waitingForDependencies;
83+
84+
clearTimeout(timeoutRef);
85+
86+
if (hasTimedOut) {
87+
console.error('Timed out waiting for dependencies');
88+
process.exitCode = 1;
89+
} else {
90+
const duration = Date.now() - startTime;
91+
console.log(`Dependencies ready in ${duration}ms`);
92+
}
7393
})();

packages/delegator-e2e/test/experimental/erc7710sendTransactionWithDelegation.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,15 +238,15 @@ test('Bob attempts to call the increment function directly', async () => {
238238
test('Bob sends a native value transaction with delegation', async () => {
239239
await deploySmartAccount(aliceSmartAccount);
240240

241-
const allowance = 100n;
241+
const maxAmount = 100n;
242242
const recipient = randomAddress();
243243

244244
const { DelegationManager: delegationManager } =
245245
aliceSmartAccount.environment;
246246

247247
const caveats = createCaveatBuilder(aliceSmartAccount.environment).addCaveat(
248248
'nativeTokenTransferAmount',
249-
allowance,
249+
{ maxAmount },
250250
);
251251

252252
const delegation = createDelegation({
@@ -268,13 +268,13 @@ test('Bob sends a native value transaction with delegation', async () => {
268268
chain,
269269
}).extend(erc7710WalletActions());
270270

271-
await fundAddress(aliceSmartAccount.address, allowance);
271+
await fundAddress(aliceSmartAccount.address, maxAmount);
272272

273273
const transactionHash = await bobWalletClient.sendTransactionWithDelegation({
274274
account: bob,
275275
chain,
276276
to: recipient,
277-
value: allowance,
277+
value: maxAmount,
278278
permissionsContext,
279279
delegationManager,
280280
});
@@ -283,5 +283,5 @@ test('Bob sends a native value transaction with delegation', async () => {
283283

284284
const balance = await publicClient.getBalance({ address: recipient });
285285

286-
expect(balance).toEqual(allowance);
286+
expect(balance).toEqual(maxAmount);
287287
});

turbo.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
"test": {
1414
"dependsOn": ["^build", "^test"]
1515
},
16-
"e2etest:full": {
17-
"dependsOn": ["^build"]
18-
},
19-
"e2etest:smoketest": {
16+
"test:e2e": {
2017
"dependsOn": ["^build"]
2118
},
2219
"test:watch": {

0 commit comments

Comments
 (0)