Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cb 5753 u tests #2964

Merged
merged 8 commits into from
Oct 18, 2024
Merged
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
3 changes: 2 additions & 1 deletion webapp/packages/core-client-activity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"clean": "rimraf --glob dist",
"lint": "eslint ./src/ --ext .ts,.tsx",
"validate-dependencies": "core-cli-validate-dependencies",
"update-ts-references": "yarn run clean && typescript-resolve-references"
"update-ts-references": "yarn run clean && typescript-resolve-references",
"test": "core-cli-test"
},
"dependencies": {
"@cloudbeaver/core-di": "^0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals';

import { ClientActivityService, INACTIVE_PERIOD_TIME } from './ClientActivityService.js';

jest.useFakeTimers();

describe('ClientActivityService', () => {
let clientActivityService: ClientActivityService;

beforeEach(() => {
clientActivityService = new ClientActivityService();

jest.spyOn(global, 'setTimeout');
jest.spyOn(global, 'clearTimeout');
});

afterEach(() => {
jest.clearAllTimers();
jest.restoreAllMocks();
});

it('should initialize with isActive set to false', () => {
expect(clientActivityService.isActive).toBe(false);
});

it('should set isActive to true when updateActivity is called', () => {
clientActivityService.updateActivity();
expect(clientActivityService.isActive).toBe(true);
});

it('should reset activity after the timeout period', () => {
clientActivityService.updateActivity();
expect(clientActivityService.isActive).toBe(true);

jest.advanceTimersByTime(INACTIVE_PERIOD_TIME);

expect(clientActivityService.isActive).toBe(false);
});

it('should clear previous timer if updateActivity is called multiple times', () => {
clientActivityService.updateActivity();
expect(setTimeout).toHaveBeenCalledTimes(1);

jest.advanceTimersByTime(Math.random() * INACTIVE_PERIOD_TIME - 1);

clientActivityService.updateActivity();
expect(clearTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenCalledTimes(2);
});

it('should clear timer and reset activity when resetActivity is called', () => {
clientActivityService.updateActivity();

jest.advanceTimersByTime(Math.random() * INACTIVE_PERIOD_TIME - 1);

clientActivityService.resetActivity();

expect(clientActivityService.isActive).toBe(false);
expect(clearTimeout).toHaveBeenCalled();
});

it('should call onActiveStateChange executor with correct value', () => {
const onActiveStateChangeSpy = jest.spyOn(clientActivityService.onActiveStateChange, 'execute');

clientActivityService.updateActivity();
expect(onActiveStateChangeSpy).toHaveBeenCalledWith(true);

jest.advanceTimersByTime(INACTIVE_PERIOD_TIME);
expect(onActiveStateChangeSpy).toHaveBeenCalledWith(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { makeObservable, observable } from 'mobx';
import { injectable } from '@cloudbeaver/core-di';
import { Executor, type IExecutor } from '@cloudbeaver/core-executor';

const INACTIVE_PERIOD_TIME = 1000 * 60;
export const INACTIVE_PERIOD_TIME = 1000 * 60;

@injectable()
export class ClientActivityService {
Expand Down
118 changes: 118 additions & 0 deletions webapp/packages/core-localization/src/LocalizationService.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { beforeEach, describe, expect, it } from '@jest/globals';

import { DEFAULT_LOCALE } from './DEFAULT_LOCALE.js';
import { type ILocale } from './ILocale.js';
import { LocalizationService } from './LocalizationService.js';

describe('LocalizationService', () => {
let service: LocalizationService;

beforeEach(() => {
service = new LocalizationService();
});

it('should initialize with default locale', () => {
service.register();
expect(service.currentLanguage).toBe(DEFAULT_LOCALE.isoCode);
expect(service.supportedLanguages.length).toBeGreaterThan(0);
sergeyteleshev marked this conversation as resolved.
Show resolved Hide resolved
});

it('should set supported languages', () => {
const locales: ILocale[] = [
{ isoCode: 'de', name: 'German', nativeName: 'Deutsch' },
{ isoCode: 'es', name: 'Spanish', nativeName: 'Español' },
];

service.setSupportedLanguages(locales);
expect(service.supportedLanguages.length).toBe(2);
});

it('should set default to first supported language', () => {
const locales: ILocale[] = [
{ isoCode: 'de', name: 'German', nativeName: 'Deutsch' },
{ isoCode: 'es', name: 'Spanish', nativeName: 'Español' },
];

service.setSupportedLanguages(locales);
expect(service.currentLanguage).toBe('de');
});

it('should return default locale if the current language is not supported', () => {
service.setLanguage('es');
expect(service.currentLanguage).toBe(DEFAULT_LOCALE.isoCode);
});

it('should throw error if there are no supported languages', () => {
service.supportedLanguages = [];
expect(() => service.currentLanguage).toThrowError('No language is available');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems weird that getter can throw an error. I suggest to add TODO to refactor this logic somewhen in the LocalizationService.ts

});

it('should change the current language', async () => {
service.register();
await service.changeLocale('ru');
expect(service.currentLanguage).toBe('ru');
});

it('should throw an error when changing to an unsupported language', async () => {
await expect(service.changeLocale('jp')).rejects.toThrowError("Language 'jp' is not supported");
});

it('should translate a token with a fallback', () => {
const token = 'greeting';
const fallback = 'Hello, World!';

service.changeLocale('en');
service['localeMap'].set('en', new Map([[token, 'Hello']]));

const translation = service.translate(token, fallback);
expect(translation).toBe('Hello');
});

it('should return fallback when translation is missing', () => {
const token = 'nonexistent_token';
const fallback = 'Fallback';

const translation = service.translate(token, fallback);
expect(translation).toBe(fallback);
});

it('should replace args in the translation string', () => {
const token = 'welcome_message';
const translationString = 'Welcome, {arg:name}!';
service['localeMap'].set('en', new Map([[token, translationString]]));
service.setLanguage('en');

const translation = service.translate(token, undefined, { name: 'John' });
expect(translation).toBe('Welcome, John!');
});
sergeyteleshev marked this conversation as resolved.
Show resolved Hide resolved

it('should replace multiple args in the translation string', () => {
const token = 'greeting_message';
const translationString = 'Hello, {arg:firstName} {arg:lastName}!';
service['localeMap'].set('en', new Map([[token, translationString]]));
service.setLanguage('en');

const translation = service.translate(token, undefined, { firstName: 'John', lastName: 'Doe' });
expect(translation).toBe('Hello, John Doe!');
});

it('should return true for supported language', () => {
service.register();

expect(service.isLanguageSupported('en')).toBe(true);
expect(service.isLanguageSupported('ru')).toBe(true);
});

it('should return false for unsupported language', () => {
service.register();

expect(service.isLanguageSupported('n/a')).toBe(false);
});
});
sergeyteleshev marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 2 additions & 1 deletion webapp/packages/core-localization/src/LocalizationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export class LocalizationService extends Bootstrap {
const firstLanguage = this.supportedLanguages[0];

if (!firstLanguage) {
throw new Error('No language is awailable');
//@TODO do not throw error in getter
throw new Error('No language is available');
}

return firstLanguage.isoCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { describe, expect, it } from '@jest/globals';

import { NodeManagerUtils } from './NodeManagerUtils.js';

describe('NodeManagerUtils', () => {
describe('connectionIdToConnectionNodeId', () => {
it('should prepend "database://" to the connectionId', () => {
const connectionId = '12345';
const result = NodeManagerUtils.connectionIdToConnectionNodeId(connectionId);
expect(result).toBe('database://12345');
});

it('should work with different connectionId values', () => {
expect(NodeManagerUtils.connectionIdToConnectionNodeId('abc')).toBe('database://abc');
expect(NodeManagerUtils.connectionIdToConnectionNodeId('')).toBe('database://');
});
});

describe('isDatabaseObject', () => {
it('should return true for objectIds starting with "database://"', () => {
expect(NodeManagerUtils.isDatabaseObject('database://123')).toBe(true);
expect(NodeManagerUtils.isDatabaseObject('database://abc')).toBe(true);
});

it('should return false for objectIds not starting with "database://"', () => {
expect(NodeManagerUtils.isDatabaseObject('http://example.com')).toBe(false);
expect(NodeManagerUtils.isDatabaseObject('12345')).toBe(false);
expect(NodeManagerUtils.isDatabaseObject('')).toBe(false);
});
});

describe('concatSchemaAndCatalog', () => {
it('should concatenate schemaId and catalogId with "@" when both are provided', () => {
const result = NodeManagerUtils.concatSchemaAndCatalog('catalog1', 'schema1');
expect(result).toBe('schema1@catalog1');
});

it('should return just schemaId if catalogId is undefined', () => {
expect(NodeManagerUtils.concatSchemaAndCatalog(undefined, 'schema1')).toBe('schema1');
});

it('should return just catalogId if schemaId is undefined', () => {
expect(NodeManagerUtils.concatSchemaAndCatalog('catalog1', undefined)).toBe('catalog1');
});

it('should return an empty string if both are undefined', () => {
expect(NodeManagerUtils.concatSchemaAndCatalog(undefined, undefined)).toBe('');
});

it('should handle cases with empty strings', () => {
expect(NodeManagerUtils.concatSchemaAndCatalog('', 'catalog1')).toBe('catalog1');
expect(NodeManagerUtils.concatSchemaAndCatalog('schema1', '')).toBe('schema1');
expect(NodeManagerUtils.concatSchemaAndCatalog('', '')).toBe('');
});
});
});
66 changes: 66 additions & 0 deletions webapp/packages/core-utils/src/getDomainFromUrl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { describe, expect, it } from '@jest/globals';

import { getDomainFromUrl } from './getDomainFromUrl.js';

describe('getDomainFromUrl', () => {
it('should return domain for a valid URL with http protocol', () => {
const url = 'http://example.com/path';
const domain = getDomainFromUrl(url);
expect(domain).toBe('example.com');
});

it('should return domain for a valid URL with https protocol', () => {
const url = 'https://example.com/path';
const domain = getDomainFromUrl(url);
expect(domain).toBe('example.com');
});

it('should return domain for a valid URL with www', () => {
const url = 'https://www.example.com/path';
const domain = getDomainFromUrl(url);
expect(domain).toBe('www.example.com');
});

it('should return domain for a URL with a subdomain', () => {
const url = 'https://blog.example.com';
const domain = getDomainFromUrl(url);
expect(domain).toBe('blog.example.com');
});

it('should return empty string for an invalid URL', () => {
const url = 'not-a-valid-url';
const domain = getDomainFromUrl(url);
expect(domain).toBe('');
});

it('should return empty string for an empty string input', () => {
const url = '';
const domain = getDomainFromUrl(url);
expect(domain).toBe('');
});

it('should return domain for a URL with query parameters', () => {
const url = 'https://example.com/search?q=test';
const domain = getDomainFromUrl(url);
expect(domain).toBe('example.com');
});

it('should return domain for a URL with port number', () => {
const url = 'https://example.com:8080/path';
const domain = getDomainFromUrl(url);
expect(domain).toBe('example.com');
});

it('should return domain for an IP address URL', () => {
const url = 'http://127.0.0.1:3000';
const domain = getDomainFromUrl(url);
expect(domain).toBe('127.0.0.1');
});
});
1 change: 0 additions & 1 deletion webapp/packages/core-utils/src/getDomainFromUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export function getDomainFromUrl(url: string): string {
const urlObject = new URL(url);
return urlObject.hostname;
} catch (e) {
console.error('Invalid URL:', e);
return '';
}
}
Loading