diff --git a/.gitignore b/.gitignore index 42ddbf8635..2b9b4269d6 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ webfonts/ *.zip build/ package-lock.json +coverage/ diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000000..c5042de1c8 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,85 @@ +// Karma configuration +// Generated on Thu Nov 16 2017 22:48:30 GMT+0100 (W. Europe Standard Time) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine', 'karma-typescript'], + + + // list of files / patterns to load in the browser + files: [ + 'src/enums/**/*.ts', + 'src/services/**/*.ts' + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + '**/*.ts': 'karma-typescript' + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress', 'karma-typescript', 'kjhtml'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity, + + client:{ + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + + karmaTypescriptConfig: { + tsconfig: './tsconfig.json', + compilerOptions: { + module: 'CommonJS' + }, + bundlerOptions: { + entrypoints: /\.spec\.ts$/ + } + }, + }) +} diff --git a/package.json b/package.json index 0a0c329293..cfdb7d6ed1 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,11 @@ "prod": "gulp build && webpack --config webpack.prod.js", "dist": "gulp build && webpack --config webpack.prod.js && gulp dist", "lint": "tslint src/**/*.ts || true", - "lint:fix": "tslint src/**/*.ts --fix" + "lint:fix": "tslint src/**/*.ts --fix", + "test": "karma start" }, "devDependencies": { + "@types/jasmine": "^2.8.2", "angular": "1.6.6", "angular-animate": "1.6.6", "angular-sweetalert": "1.1.2", @@ -37,7 +39,16 @@ "gulp-zip": "4.0.0", "html-loader": "^0.5.1", "html-webpack-plugin": "^2.30.1", + "jasmine-core": "^2.8.0", + "jasmine-spec-reporter": "^4.2.1", "jshint": "2.9.5", + "karma": "^1.7.1", + "karma-chrome-launcher": "^2.2.0", + "karma-cli": "^1.0.1", + "karma-coverage-istanbul-reporter": "^1.3.0", + "karma-jasmine": "^1.1.0", + "karma-jasmine-html-reporter": "^0.2.2", + "karma-typescript": "^3.0.8", "less": "^3.0.0-alpha.3", "less-loader": "^4.0.5", "ng-infinite-scroll": "1.3.0", diff --git a/src/services/utils.service.spec.ts b/src/services/utils.service.spec.ts new file mode 100644 index 0000000000..d52e92a05e --- /dev/null +++ b/src/services/utils.service.spec.ts @@ -0,0 +1,54 @@ +import UtilsService from './utils.service'; + +describe('Utils Service', () => { + describe('getDomain', () => { + it('should fail for invalid urls', () => { + expect(UtilsService.getDomain(null)).toBeNull(); + expect(UtilsService.getDomain(undefined)).toBeNull(); + expect(UtilsService.getDomain(' ')).toBeNull(); + expect(UtilsService.getDomain('https://bit!:"_&ward.com')).toBeNull(); + expect(UtilsService.getDomain('bitwarden')).toBeNull(); + }); + + it('should handle urls without protocol', () => { + expect(UtilsService.getDomain('bitwarden.com')).toBe('bitwarden.com'); + expect(UtilsService.getDomain('wrong://bitwarden.com')).toBe('bitwarden.com'); + }); + + it('should handle valid urls', () => { + expect(UtilsService.getDomain('https://bitwarden')).toBe('bitwarden'); + expect(UtilsService.getDomain('https://bitwarden.com')).toBe('bitwarden.com'); + expect(UtilsService.getDomain('http://bitwarden.com')).toBe('bitwarden.com'); + expect(UtilsService.getDomain('http://vault.bitwarden.com')).toBe('bitwarden.com'); + expect(UtilsService.getDomain('https://user:password@bitwarden.com:8080/password/sites?and&query#hash')).toBe('bitwarden.com'); + expect(UtilsService.getDomain('https://bitwarden.unknown')).toBe('bitwarden.unknown'); + }); + + it('should support localhost and IP', () => { + expect(UtilsService.getDomain('https://localhost')).toBe('localhost'); + expect(UtilsService.getDomain('https://192.168.1.1')).toBe('192.168.1.1'); + }); + }); + + describe('getHostname', () => { + it('should fail for invalid urls', () => { + expect(UtilsService.getHostname(null)).toBeNull(); + expect(UtilsService.getHostname(undefined)).toBeNull(); + expect(UtilsService.getHostname(' ')).toBeNull(); + expect(UtilsService.getHostname('https://bit!:"_&ward.com')).toBeNull(); + expect(UtilsService.getHostname('bitwarden')).toBeNull(); + }); + + it('should handle valid urls', () => { + expect(UtilsService.getHostname('https://bitwarden.com')).toBe('bitwarden.com'); + expect(UtilsService.getHostname('http://bitwarden.com')).toBe('bitwarden.com'); + expect(UtilsService.getHostname('http://vault.bitwarden.com')).toBe('vault.bitwarden.com'); + expect(UtilsService.getHostname('https://user:password@bitwarden.com:8080/password/sites?and&query#hash')).toBe('bitwarden.com'); + }); + + it('should support localhost and IP', () => { + expect(UtilsService.getHostname('https://localhost')).toBe('localhost'); + expect(UtilsService.getHostname('https://192.168.1.1')).toBe('192.168.1.1'); + }); + }); +}); diff --git a/src/services/utils.service.ts b/src/services/utils.service.ts index abe45c3d44..357939db3d 100644 --- a/src/services/utils.service.ts +++ b/src/services/utils.service.ts @@ -1,3 +1,4 @@ +import * as tldjs from 'tldjs'; import { BrowserType } from '../enums/browserType.enum'; import { UtilsService as UtilsServiceInterface } from './abstractions/utils.service'; @@ -186,28 +187,19 @@ export default class UtilsService implements UtilsServiceInterface { if (uriString.startsWith('http://') || uriString.startsWith('https://')) { try { const url = new URL(uriString); - if (!url.hostname) { - return null; - } if (url.hostname === 'localhost' || UtilsService.validIpAddress(url.hostname)) { return url.hostname; } - if (typeof tldjs !== 'undefined' && tldjs) { - const domain = tldjs.getDomain(url.hostname); - if (domain != null) { - return domain; - } - } - - return url.hostname; + const domain = tldjs.getDomain(url.hostname); + return domain ? domain : url.hostname; } catch (e) { } - } else if (typeof tldjs !== 'undefined' && tldjs) { - const domain = tldjs.getDomain(uriString); - if (domain != null) { - return domain; - } + } + + const domain = tldjs.getDomain(uriString); + if (domain != null) { + return domain; } return null; @@ -226,10 +218,6 @@ export default class UtilsService implements UtilsServiceInterface { if (uriString.startsWith('http://') || uriString.startsWith('https://')) { try { const url = new URL(uriString); - if (!url.hostname) { - return null; - } - return url.hostname; } catch (e) { } } diff --git a/tsconfig.json b/tsconfig.json index e1fb72efff..bb80f8cd9e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,10 @@ "module": "es6", "target": "ES2016", "allowJs": true, - "sourceMap": true + "sourceMap": true, + "types": [ + "jasmine" + ] }, "exclude": [ "node_modules",