feat: bridges, PMM, flash workflow, token-aggregation, and deployment docs
- CCIP/trustless bridge contracts, GRU tokens, DEX/PMM tests, reserve vault. - Token-aggregation service routes, planner, chain config, relay env templates. - Config snapshots and multi-chain deployment markdown updates. - gitignore services/btc-intake/dist/ (tsc output); do not track dist. Run forge build && forge test before deploy (large solc graph). Made-with: Cursor
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
# API Tests
|
||||
|
||||
This directory contains integration and contract tests for the eMoney Token Factory API.
|
||||
This directory contains reference contract tests and opt-in integration smoke tests for the eMoney control-plane API surface.
|
||||
|
||||
The default repo validation pass does not start an external REST or GraphQL control-plane service, so the integration suites are intentionally opt-in.
|
||||
|
||||
## Test Structure
|
||||
|
||||
```
|
||||
test/api/
|
||||
├── integration/ # Integration tests
|
||||
test/emoney/api/
|
||||
├── integration/ # Optional smoke tests against an external API service
|
||||
│ ├── rest-api.test.ts
|
||||
│ └── graphql.test.ts
|
||||
└── contract/ # Contract validation tests
|
||||
@@ -14,6 +16,8 @@ test/api/
|
||||
└── event-schema-validation.test.ts
|
||||
```
|
||||
|
||||
Reference API specs used by the contract tests live under `test/api/packages/`.
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
@@ -39,6 +43,13 @@ Test actual API endpoints against running services:
|
||||
- GraphQL queries and mutations
|
||||
- End-to-end flows
|
||||
|
||||
Enable them explicitly:
|
||||
|
||||
```bash
|
||||
export RUN_EMONEY_API_INTEGRATION=1
|
||||
export RUN_EMONEY_GRAPHQL_INTEGRATION=1
|
||||
```
|
||||
|
||||
### Contract Tests
|
||||
|
||||
Validate that implementations conform to specifications:
|
||||
@@ -48,25 +59,10 @@ Validate that implementations conform to specifications:
|
||||
|
||||
## Mock Servers
|
||||
|
||||
Use mock servers for testing without requiring full infrastructure:
|
||||
|
||||
```bash
|
||||
# Start all mock servers
|
||||
cd api/tools/mock-server
|
||||
pnpm run start:all
|
||||
|
||||
# Or start individually
|
||||
pnpm run start:rest # REST API mock (port 4010)
|
||||
pnpm run start:graphql # GraphQL mock (port 4020)
|
||||
```
|
||||
|
||||
## Test Environment
|
||||
|
||||
Set environment variables:
|
||||
Mock server tooling is not checked into this monorepo checkout. If you have an external mock or implementation, point the integration tests at it with environment variables.
|
||||
|
||||
```bash
|
||||
export API_URL=http://localhost:3000
|
||||
export GRAPHQL_URL=http://localhost:4000/graphql
|
||||
export ACCESS_TOKEN=your-test-token
|
||||
```
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('AsyncAPI Event Schema Validation', () => {
|
||||
];
|
||||
|
||||
requiredChannels.forEach((channel) => {
|
||||
expect(asyncapiSpec.channels).toHaveProperty(channel);
|
||||
expect(asyncapiSpec.channels[channel]).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -61,4 +61,3 @@ describe('AsyncAPI Event Schema Validation', () => {
|
||||
expect(envelopeSchema.required).toContain('payload');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,8 +6,40 @@ import { describe, it, expect, beforeAll } from '@jest/globals';
|
||||
import { GraphQLClient } from 'graphql-request';
|
||||
|
||||
const GRAPHQL_URL = process.env.GRAPHQL_URL || 'http://localhost:4000/graphql';
|
||||
const runIntegration = process.env.RUN_EMONEY_GRAPHQL_INTEGRATION === '1';
|
||||
const describeIfConfigured = runIntegration ? describe : describe.skip;
|
||||
|
||||
describe('GraphQL API Integration Tests', () => {
|
||||
type TokenQueryResult = {
|
||||
token: {
|
||||
code: string;
|
||||
address: string;
|
||||
name: string;
|
||||
symbol: string;
|
||||
policy: {
|
||||
lienMode: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
type TriggersQueryResult = {
|
||||
triggers: {
|
||||
items: Array<{
|
||||
triggerId: string;
|
||||
rail: string;
|
||||
state: string;
|
||||
}>;
|
||||
total: number;
|
||||
};
|
||||
};
|
||||
|
||||
type DeployTokenMutationResult = {
|
||||
deployToken: {
|
||||
code: string;
|
||||
address: string;
|
||||
};
|
||||
};
|
||||
|
||||
describeIfConfigured('GraphQL API Integration Tests', () => {
|
||||
let client: GraphQLClient;
|
||||
|
||||
beforeAll(() => {
|
||||
@@ -34,7 +66,7 @@ describe('GraphQL API Integration Tests', () => {
|
||||
}
|
||||
`;
|
||||
|
||||
const data = await client.request(query, { code: 'USDW' });
|
||||
const data = await client.request<TokenQueryResult>(query, { code: 'USDW' });
|
||||
expect(data).toHaveProperty('token');
|
||||
expect(data.token).toHaveProperty('code');
|
||||
});
|
||||
@@ -53,7 +85,7 @@ describe('GraphQL API Integration Tests', () => {
|
||||
}
|
||||
`;
|
||||
|
||||
const data = await client.request(query, {
|
||||
const data = await client.request<TriggersQueryResult>(query, {
|
||||
filter: { state: 'PENDING' },
|
||||
paging: { limit: 10, offset: 0 },
|
||||
});
|
||||
@@ -74,7 +106,7 @@ describe('GraphQL API Integration Tests', () => {
|
||||
}
|
||||
`;
|
||||
|
||||
const data = await client.request(mutation, {
|
||||
const data = await client.request<DeployTokenMutationResult>(mutation, {
|
||||
input: {
|
||||
name: 'Test Token',
|
||||
symbol: 'TEST',
|
||||
@@ -88,4 +120,3 @@ describe('GraphQL API Integration Tests', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -7,13 +7,14 @@ import axios from 'axios';
|
||||
|
||||
const BASE_URL = process.env.API_URL || 'http://localhost:3000';
|
||||
const API_KEY = process.env.API_KEY || 'test-key';
|
||||
const runIntegration = process.env.RUN_EMONEY_API_INTEGRATION === '1';
|
||||
const describeIfConfigured = runIntegration ? describe : describe.skip;
|
||||
|
||||
describe('REST API Integration Tests', () => {
|
||||
describeIfConfigured('REST API Integration Tests', () => {
|
||||
let accessToken: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
// TODO: Get OAuth2 token
|
||||
// accessToken = await getAccessToken();
|
||||
accessToken = process.env.ACCESS_TOKEN || 'test-token';
|
||||
});
|
||||
|
||||
describe('Token Operations', () => {
|
||||
@@ -102,4 +103,3 @@ describe('REST API Integration Tests', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"description": "API integration and contract tests",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:ci": "jest --runInBand",
|
||||
"test:integration": "jest --testPathPattern=integration",
|
||||
"test:contract": "jest --testPathPattern=contract",
|
||||
"test:watch": "jest --watch"
|
||||
@@ -28,7 +29,10 @@
|
||||
"preset": "ts-jest",
|
||||
"testEnvironment": "node",
|
||||
"testMatch": [
|
||||
"**/test/**/*.test.ts"
|
||||
"**/*.test.ts"
|
||||
],
|
||||
"testPathIgnorePatterns": [
|
||||
"/node_modules/"
|
||||
],
|
||||
"collectCoverageFrom": [
|
||||
"api/services/**/*.ts",
|
||||
@@ -37,4 +41,3 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
test/emoney/api/tsconfig.json
Normal file
18
test/emoney/api/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": false,
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"node",
|
||||
"jest"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./**/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user