Skip to content

Commit 6253e5d

Browse files
authored
Merge pull request #138 from Achievers-sketch/main
Implement live contributor activity tracking and profile fetching
2 parents c3a5716 + a50056f commit 6253e5d

14 files changed

Lines changed: 797 additions & 112 deletions

File tree

.github/workflows/ci.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ '**' ]
6+
pull_request:
7+
branches: [ '**' ]
8+
9+
jobs:
10+
test:
11+
name: Run tests
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: '20'
21+
cache: 'npm'
22+
23+
- name: Install dependencies
24+
run: npm ci
25+
26+
- name: Run tests
27+
run: npm test --if-present

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
> A full-stack Next.js 14 dashboard for **Vero Guardians** — trusted on-chain reviewers who cast cryptographically-signed votes on GitHub pull requests via the Stellar blockchain.
44
5+
<!-- CI badges: update OWNER/REPO to your GitHub repo -->
6+
[![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg)](https://github.com/OWNER/REPO/actions/workflows/ci.yml)
7+
[![Tests](https://img.shields.io/badge/tests-passing-brightgreen)](#)
8+
9+
510
Guardians connect their [Freighter](https://www.freighter.app/) wallet, browse the live PR review feed, and submit approval votes recorded as permanent `manageData` transactions on Stellar Horizon. The system bridges open-source code review with decentralized, verifiable trust.
611

712
---

jest.setup.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,37 @@
11
import '@testing-library/jest-dom';
22
import './src/i18n/config';
3+
import { installIndexedDBMock } from './test-utils/indexeddb-mock';
4+
5+
// Mock File System Access API (showSaveFilePicker)
6+
if (typeof globalThis.window === 'undefined') {
7+
// running in node - provide a minimal window and document
8+
globalThis.window = globalThis;
9+
}
10+
11+
if (!('showSaveFilePicker' in globalThis)) {
12+
globalThis.showSaveFilePicker = async (options = {}) => {
13+
const chunks = [];
14+
return {
15+
createWritable: async () => ({
16+
write: async (data) => {
17+
// accept Blob or write request
18+
if (data instanceof Blob) {
19+
const array = new Uint8Array(await data.arrayBuffer());
20+
chunks.push(array);
21+
} else if (data && data.data instanceof Blob) {
22+
const array = new Uint8Array(await data.data.arrayBuffer());
23+
chunks.push(array);
24+
}
25+
},
26+
close: async () => {},
27+
}),
28+
};
29+
};
30+
}
31+
32+
// Install enhanced IndexedDB mock for tests
33+
try {
34+
installIndexedDBMock();
35+
} catch (e) {
36+
// ignore if already installed or environment prevents it
37+
}

package-lock.json

Lines changed: 0 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import { render, act } from '@testing-library/react';
3+
import { useEvents } from '@/hooks/useEvents';
4+
import { useActivityStream } from '@/hooks/useActivityStream';
5+
import ActivityLogExport from '@/components/ActivityLogExport/ActivityLogExport';
6+
import * as logger from '@/utils/logger';
7+
8+
jest.mock('@/utils/logger');
9+
10+
function EventEmitterTestApp() {
11+
const { emit } = useEvents();
12+
useActivityStream();
13+
return (
14+
<div>
15+
<button onClick={() => emit({ type: 'vote', actor: 'GABC' })}>emit</button>
16+
<ActivityLogExport />
17+
</div>
18+
);
19+
}
20+
21+
describe('integration: event -> persist -> export listener', () => {
22+
beforeEach(() => jest.resetAllMocks());
23+
24+
it('calls appendAuditEvent when emitting an event and exporter observes persisted records', async () => {
25+
const append = jest.spyOn(logger, 'appendAuditEvent').mockResolvedValue({} as any);
26+
const read = jest.spyOn(logger, 'readEncryptedAuditLogs').mockReturnValue([{
27+
id: 'r1', timestamp: new Date().toISOString(), sequence: 1, version: 1, algorithm: 'AES-GCM', iv: 'iv', ciphertext: 'ct', previousHash: '0', hash: 'h1'
28+
} as any]);
29+
30+
const { getByText } = render(<EventEmitterTestApp />);
31+
32+
act(() => {
33+
getByText('emit').click();
34+
});
35+
36+
// allow async append and listener
37+
await new Promise((r) => setTimeout(r, 0));
38+
39+
expect(append).toHaveBeenCalled();
40+
});
41+
});

0 commit comments

Comments
 (0)