Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/backend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,29 @@ jobs:
- name: TypeScript compilation
run: npm run build

- name: Generate OpenAPI spec
run: npm run generate:openapi

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: backend-dist
path: BackEnd/dist/
retention-days: 7

- name: Upload OpenAPI artifact
uses: actions/upload-artifact@v4
with:
name: backend-openapi-spec
path: BackEnd/docs/openapi.json
retention-days: 7

- name: Check OpenAPI spec diff
if: github.event_name == 'pull_request'
run: |
git diff --exit-code -- docs/openapi.json
shell: bash

- name: Lint
run: npm run lint

Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/frontend-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ jobs:
- name: Tests
run: npm run test

# Install Playwright browser and run critical E2E journeys
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium

- name: E2E tests
run: npm run test:e2e -- --project=chromium

# Build Next.js app
- name: Build
run: npm run build
Expand Down
42 changes: 42 additions & 0 deletions BackEnd/docs/openapi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"openapi": "3.0.0",
"info": {
"title": "StellarEarn API",
"description": "Quest-based earning platform on Stellar blockchain\n\nSupported API versions: v1, v2. Use path versioning (/api/v1/*, /api/v2/*) and/or header versioning (X-API-Version: 1).",
"version": "0.0.1"
},
"servers": [
{
"url": "/api/v1",
"description": "API v1"
},
{
"url": "/api/v2",
"description": "API v2"
}
],
"tags": [
{
"name": "Authentication"
},
{
"name": "Health",
"description": "System health and readiness probes"
}
],
"paths": {},
"components": {
"securitySchemes": {
"JWT-auth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
},
"security": [
{
"JWT-auth": []
}
]
}
1 change: 1 addition & 0 deletions BackEnd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"test:integration": "jest --clearCache && jest --config ./test/jest-integration.json",
"db:backup": "ts-node scripts/db-backup.ts",
"db:rollback": "ts-node scripts/db-rollback.ts",
"generate:openapi": "nest start --entryFile generate-openapi",
"typeorm": "typeorm-ts-node-commonjs -d src/database/data-source.ts",
"migration:generate": "bun run typeorm -- migration:generate",
"migration:create": "typeorm migration:create",
Expand Down
2 changes: 2 additions & 0 deletions BackEnd/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
},
];

const isOpenApiGeneration = process.env.GENERATE_OPENAPI === 'true';

@Module({

Check failure on line 68 in BackEnd/src/app.module.ts

View workflow job for this annotation

GitHub Actions / Lint & Format Check

'isOpenApiGeneration' is assigned a value but never used. Allowed unused vars must match /^_/u
imports: [
ConfigModule.forRoot({
isGlobal: true,
Expand Down
4 changes: 4 additions & 0 deletions BackEnd/src/config/swagger.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
API_VERSION_POLICY_PATH,
} from './versioning.config';

const packageJson = require('../../package.json') as { version: string };

Check failure on line 10 in BackEnd/src/config/swagger.config.ts

View workflow job for this annotation

GitHub Actions / Lint & Format Check

A `require()` style import is forbidden

Check failure on line 10 in BackEnd/src/config/swagger.config.ts

View workflow job for this annotation

GitHub Actions / Lint & Format Check

'packageJson' is assigned a value but never used. Allowed unused vars must match /^_/u

export function setupSwagger(
app: INestApplication,
configService?: ConfigService,
Expand Down Expand Up @@ -46,4 +48,6 @@
SwaggerModule.setup('api/docs', app, document, {
swaggerOptions: { persistAuthorization: true },
});

return document;
}
48 changes: 48 additions & 0 deletions BackEnd/src/generate-openapi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { VersioningType } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import * as fs from 'fs';
import * as path from 'path';
import {
API_VERSION_CONFIG,
extractApiVersion,
} from './config/versioning.config';
import { setupSwagger } from './config/swagger.config';

async function generateOpenApiSpec(): Promise<void> {
process.env.GENERATE_OPENAPI = 'true';

const { AppModule } = await import('./app.module');

const app = await NestFactory.create(AppModule, {
logger: false,
});

const configService = app.get(ConfigService);

app.setGlobalPrefix('api');
app.enableVersioning({
type: VersioningType.CUSTOM,
defaultVersion: API_VERSION_CONFIG.defaultVersion,
extractor: (request) => {
return (
extractApiVersion(request as any) || API_VERSION_CONFIG.defaultVersion
);
},
});

const document = setupSwagger(app, configService);

const outputPath = path.resolve(process.cwd(), 'docs/openapi.json');
await fs.promises.mkdir(path.dirname(outputPath), { recursive: true });
await fs.promises.writeFile(outputPath, `${JSON.stringify(document, null, 2)}\n`);

console.log(`OpenAPI spec written to ${outputPath}`);

await app.close();
}

generateOpenApiSpec().catch((error) => {
console.error('Failed to generate OpenAPI spec', error);
process.exit(1);
});
32 changes: 32 additions & 0 deletions FrontEnd/my-app/context/WalletContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,27 @@ interface WalletContextType {

const WalletContext = createContext<WalletContextType | undefined>(undefined);

const createMockWalletKit = () => {
const mockAddress =
(typeof window !== 'undefined' &&
(window as Window & {
__PLAYWRIGHT_MOCK_WALLET_ADDRESS__?: string;
}).__PLAYWRIGHT_MOCK_WALLET_ADDRESS__) ||
'GCLN3QY2X7V4R5J6K8M9P0Q1R2S3T4U5V6W7X8Y9Z0A1B2C3D4E5F6G7H8J9K';

return {
setWallet: async () => undefined,
getAddress: async () => ({ address: mockAddress }),
disconnect: async () => undefined,
sign: async ({ payload }: { payload: string }) => ({
result: `mock-signature:${payload}`,
}),
signTransaction: async (xdr: string) => ({
signedTxXdr: `mock-signed:${xdr}`,
}),
};
};

export const useWallet = () => {
const context = useContext(WalletContext);
if (!context)
Expand Down Expand Up @@ -52,6 +73,17 @@ export const WalletProvider = ({ children }: { children: React.ReactNode }) => {

useEffect(() => {
const initKit = async () => {
const isMockWalletEnabled =
typeof window !== 'undefined' &&
(window as Window & {
__PLAYWRIGHT_MOCK_WALLET__?: string;
}).__PLAYWRIGHT_MOCK_WALLET__ === 'true';

if (isMockWalletEnabled) {
setKit(createMockWalletKit());
return;
}

try {
const walletKitModule = await import('@creit.tech/stellar-wallets-kit');
const kitInstance = new walletKitModule.StellarWalletsKit({
Expand Down
1 change: 1 addition & 0 deletions FrontEnd/my-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"typecheck": "tsc --noEmit",
"validate:path-aliases": "node scripts/validate-path-aliases.js",
"test": "vitest run",
"test:e2e": "playwright test --config=playwright.config.ts",
"test:unit": "vitest run --exclude '**/*.integration.test.ts'",
"test:integration": "vitest run --include '**/*.integration.test.ts'",
"test:watch": "vitest",
Expand Down
8 changes: 7 additions & 1 deletion FrontEnd/my-app/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ export default defineConfig({
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: process.env.E2E_BASE_URL || 'http://localhost:3000',
baseURL: process.env.E2E_BASE_URL || 'http://127.0.0.1:3000',
trace: 'on-first-retry',
},
webServer: {
command: 'npm run dev -- --hostname 127.0.0.1',
url: 'http://127.0.0.1:3000',
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
projects: [
{
name: 'chromium',
Expand Down
Loading
Loading