Skip to content

Commit

Permalink
Cb 5753 u tests (#2964)
Browse files Browse the repository at this point in the history
* CB-5753 add localization service test, fix grammar

* CB-5753 add test for the getDomainFromUrl

* CB-5753 add test for the client activity service

* CB-5753 add NodeManagerUtils tests

* CB-5753 add more cases

* CB-5753 pass args correctly
  • Loading branch information
devnaumov authored Oct 18, 2024
1 parent e62538b commit 115cfb3
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 4 deletions.
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);
});

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');
});

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!');
});

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);
});
});
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 '';
}
}

0 comments on commit 115cfb3

Please sign in to comment.