Skip to content

Commit

Permalink
test: add core modules test cases (janhq#3498)
Browse files Browse the repository at this point in the history
* chore: add core module test cases

* chore: fix tests

* chore: add code coverage report

* chore: split coverage step

* chore: split coverage step

* Update jan-electron-linter-and-test.yml

* Update jan-electron-linter-and-test.yml

* Update jan-electron-linter-and-test.yml

* chore: update tests

* chore: add web utils test cases

* chore: add restful and helper tests

* chore: add tests
  • Loading branch information
louis-jan authored Sep 6, 2024
1 parent f759fae commit 846efb3
Show file tree
Hide file tree
Showing 46 changed files with 1,194 additions and 19 deletions.
74 changes: 74 additions & 0 deletions .github/workflows/jan-electron-linter-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ on:
- '!README.md'

jobs:

base_branch_cov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.base_ref }}
- name: Use Node.js v20.9.0
uses: actions/setup-node@v3
with:
node-version: v20.9.0

- name: Install dependencies
run: yarn

- name: Run test coverage
run: yarn test:coverage

- name: Upload code coverage for ref branch
uses: actions/upload-artifact@v3
with:
name: ref-lcov.info
path: ./coverage/lcov.info

test-on-macos:
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
runs-on: [self-hosted, macOS, macos-desktop]
Expand Down Expand Up @@ -292,6 +316,56 @@ jobs:
TURBO_TEAM: 'linux'
TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'

coverage-check:
runs-on: [self-hosted, Linux, ubuntu-desktop]
needs: base_branch_cov
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
- name: Getting the repo
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Installing node
uses: actions/setup-node@v3
with:
node-version: 20

- name: 'Cleanup cache'
continue-on-error: true
run: |
rm -rf ~/jan
make clean
- name: Download code coverage report from base branch
uses: actions/download-artifact@v3
with:
name: ref-lcov.info

- name: Linter and test coverage
run: |
export DISPLAY=$(w -h | awk 'NR==1 {print $2}')
echo -e "Display ID: $DISPLAY"
npm config set registry ${{ secrets.NPM_PROXY }} --global
yarn config set registry ${{ secrets.NPM_PROXY }} --global
make lint
yarn build:test
yarn test:coverage
env:
TURBO_API: '${{ secrets.TURBO_API }}'
TURBO_TEAM: 'linux'
TURBO_TOKEN: '${{ secrets.TURBO_TOKEN }}'

- name: Generate Code Coverage report
id: code-coverage
uses: barecheck/code-coverage-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
lcov-file: "./coverage/lcov.info"
base-lcov-file: "./lcov.info"
send-summary-comment: true
show-annotations: "warning"

test-on-ubuntu-pr-target:
runs-on: [self-hosted, Linux, ubuntu-desktop]
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ extensions/*-extension/bin/vulkaninfo
.turbo
electron/test-data
electron/test-results
core/test_results.html
coverage
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ endif
# Testing
test: lint
yarn build:test
yarn test:unit
yarn test:coverage
yarn test

# Builds and publishes the app
Expand Down
1 change: 1 addition & 0 deletions core/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ module.exports = {
moduleNameMapper: {
'@/(.*)': '<rootDir>/src/$1',
},
runner: './testRunner.js',
}
4 changes: 3 additions & 1 deletion core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,16 @@
"eslint": "8.57.0",
"eslint-plugin-jest": "^27.9.0",
"jest": "^29.7.0",
"jest-junit": "^16.0.0",
"jest-runner": "^29.7.0",
"rimraf": "^3.0.2",
"rollup": "^2.38.5",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-json": "^3.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"ts-jest": "^29.1.2",
"ts-jest": "^29.2.5",
"tslib": "^2.6.2",
"typescript": "^5.3.3"
},
Expand Down
98 changes: 98 additions & 0 deletions core/src/browser/core.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { openExternalUrl } from './core';
import { joinPath } from './core';
import { openFileExplorer } from './core';
import { getJanDataFolderPath } from './core';
import { abortDownload } from './core';
import { getFileSize } from './core';
import { executeOnMain } from './core';

it('should open external url', async () => {
const url = 'http://example.com';
globalThis.core = {
api: {
openExternalUrl: jest.fn().mockResolvedValue('opened')
}
};
const result = await openExternalUrl(url);
expect(globalThis.core.api.openExternalUrl).toHaveBeenCalledWith(url);
expect(result).toBe('opened');
});


it('should join paths', async () => {
const paths = ['/path/one', '/path/two'];
globalThis.core = {
api: {
joinPath: jest.fn().mockResolvedValue('/path/one/path/two')
}
};
const result = await joinPath(paths);
expect(globalThis.core.api.joinPath).toHaveBeenCalledWith(paths);
expect(result).toBe('/path/one/path/two');
});


it('should open file explorer', async () => {
const path = '/path/to/open';
globalThis.core = {
api: {
openFileExplorer: jest.fn().mockResolvedValue('opened')
}
};
const result = await openFileExplorer(path);
expect(globalThis.core.api.openFileExplorer).toHaveBeenCalledWith(path);
expect(result).toBe('opened');
});


it('should get jan data folder path', async () => {
globalThis.core = {
api: {
getJanDataFolderPath: jest.fn().mockResolvedValue('/path/to/jan/data')
}
};
const result = await getJanDataFolderPath();
expect(globalThis.core.api.getJanDataFolderPath).toHaveBeenCalled();
expect(result).toBe('/path/to/jan/data');
});


it('should abort download', async () => {
const fileName = 'testFile';
globalThis.core = {
api: {
abortDownload: jest.fn().mockResolvedValue('aborted')
}
};
const result = await abortDownload(fileName);
expect(globalThis.core.api.abortDownload).toHaveBeenCalledWith(fileName);
expect(result).toBe('aborted');
});


it('should get file size', async () => {
const url = 'http://example.com/file';
globalThis.core = {
api: {
getFileSize: jest.fn().mockResolvedValue(1024)
}
};
const result = await getFileSize(url);
expect(globalThis.core.api.getFileSize).toHaveBeenCalledWith(url);
expect(result).toBe(1024);
});


it('should execute function on main process', async () => {
const extension = 'testExtension';
const method = 'testMethod';
const args = ['arg1', 'arg2'];
globalThis.core = {
api: {
invokeExtensionFunc: jest.fn().mockResolvedValue('result')
}
};
const result = await executeOnMain(extension, method, ...args);
expect(globalThis.core.api.invokeExtensionFunc).toHaveBeenCalledWith(extension, method, ...args);
expect(result).toBe('result');
});
37 changes: 37 additions & 0 deletions core/src/browser/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { events } from './events';
import { jest } from '@jest/globals';

it('should emit an event', () => {
const mockObject = { key: 'value' };
globalThis.core = {
events: {
emit: jest.fn()
}
};
events.emit('testEvent', mockObject);
expect(globalThis.core.events.emit).toHaveBeenCalledWith('testEvent', mockObject);
});


it('should remove an observer for an event', () => {
const mockHandler = jest.fn();
globalThis.core = {
events: {
off: jest.fn()
}
};
events.off('testEvent', mockHandler);
expect(globalThis.core.events.off).toHaveBeenCalledWith('testEvent', mockHandler);
});


it('should add an observer for an event', () => {
const mockHandler = jest.fn();
globalThis.core = {
events: {
on: jest.fn()
}
};
events.on('testEvent', mockHandler);
expect(globalThis.core.events.on).toHaveBeenCalledWith('testEvent', mockHandler);
});
46 changes: 46 additions & 0 deletions core/src/browser/extension.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { BaseExtension } from './extension'

class TestBaseExtension extends BaseExtension {
onLoad(): void {}
onUnload(): void {}
}

describe('BaseExtension', () => {
let baseExtension: TestBaseExtension

beforeEach(() => {
baseExtension = new TestBaseExtension('https://example.com', 'TestExtension')
})

afterEach(() => {
jest.resetAllMocks()
})

it('should have the correct properties', () => {
expect(baseExtension.name).toBe('TestExtension')
expect(baseExtension.productName).toBeUndefined()
expect(baseExtension.url).toBe('https://example.com')
expect(baseExtension.active).toBeUndefined()
expect(baseExtension.description).toBeUndefined()
expect(baseExtension.version).toBeUndefined()
})

it('should return undefined for type()', () => {
expect(baseExtension.type()).toBeUndefined()
})

it('should have abstract methods onLoad() and onUnload()', () => {
expect(baseExtension.onLoad).toBeDefined()
expect(baseExtension.onUnload).toBeDefined()
})

it('should have installationState() return "NotRequired"', async () => {
const installationState = await baseExtension.installationState()
expect(installationState).toBe('NotRequired')
})

it('should install the extension', async () => {
await baseExtension.install()
// Add your assertions here
})
})
60 changes: 60 additions & 0 deletions core/src/browser/extensions/engines/helpers/sse.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { lastValueFrom, Observable } from 'rxjs'
import { requestInference } from './sse'

describe('requestInference', () => {
it('should send a request to the inference server and return an Observable', () => {
// Mock the fetch function
const mockFetch: any = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ choices: [{ message: { content: 'Generated response' } }] }),
headers: new Headers(),
redirected: false,
status: 200,
statusText: 'OK',
// Add other required properties here
})
)
jest.spyOn(global, 'fetch').mockImplementation(mockFetch)

// Define the test inputs
const inferenceUrl = 'https://inference-server.com'
const requestBody = { message: 'Hello' }
const model = { id: 'model-id', parameters: { stream: false } }

// Call the function
const result = requestInference(inferenceUrl, requestBody, model)

// Assert the expected behavior
expect(result).toBeInstanceOf(Observable)
expect(lastValueFrom(result)).resolves.toEqual('Generated response')
})

it('returns 401 error', () => {
// Mock the fetch function
const mockFetch: any = jest.fn(() =>
Promise.resolve({
ok: false,
json: () => Promise.resolve({ error: { message: 'Wrong API Key', code: 'invalid_api_key' } }),
headers: new Headers(),
redirected: false,
status: 401,
statusText: 'invalid_api_key',
// Add other required properties here
})
)
jest.spyOn(global, 'fetch').mockImplementation(mockFetch)

// Define the test inputs
const inferenceUrl = 'https://inference-server.com'
const requestBody = { message: 'Hello' }
const model = { id: 'model-id', parameters: { stream: false } }

// Call the function
const result = requestInference(inferenceUrl, requestBody, model)

// Assert the expected behavior
expect(result).toBeInstanceOf(Observable)
expect(lastValueFrom(result)).rejects.toEqual({ message: 'Wrong API Key', code: 'invalid_api_key' })
})
})
Loading

0 comments on commit 846efb3

Please sign in to comment.