diff --git a/extensions/chromium/runet-censorship-bypass/gulpfile.js b/extensions/chromium/runet-censorship-bypass/gulpfile.js index 41da081..6e2e890 100644 --- a/extensions/chromium/runet-censorship-bypass/gulpfile.js +++ b/extensions/chromium/runet-censorship-bypass/gulpfile.js @@ -52,13 +52,16 @@ gulp.task('clean', function() { const contexts = require('./src/templates-data').contexts; +const woTests = ['!./src/**/test', '!./src/**/test/**/*']; +const srcWoTests = ['./src/extension-common/**/*', ...woTests]; + gulp.task('_cp-common', ['clean'], function() { - gulp.src(['./src/extension-common/**/*']) + gulp.src(srcWoTests) .pipe(templatePlugin(contexts.mini)) .pipe(gulp.dest('./build/extension-mini')) - gulp.src(['./src/extension-common/**/*']) + gulp.src(srcWoTests) .pipe(templatePlugin(contexts.full)) .pipe(gulp.dest('./build/extension-full')); @@ -66,7 +69,7 @@ gulp.task('_cp-common', ['clean'], function() { gulp.task('_cp-mini', ['_cp-common'], function() { - gulp.src(['./src/extension-mini/**/*']) + gulp.src(['./src/extension-mini/**/*', ...woTests]) .pipe(templatePlugin(contexts.mini)) .pipe(gulp.dest('./build/extension-mini')); @@ -74,7 +77,7 @@ gulp.task('_cp-mini', ['_cp-common'], function() { gulp.task('_cp-full', ['_cp-common'], function() { - gulp.src(['./src/extension-full/**/*']) + gulp.src(['./src/extension-full/**/*', ...woTests]) .pipe(templatePlugin(contexts.full)) .pipe(gulp.dest('./build/extension-full')); diff --git a/extensions/chromium/runet-censorship-bypass/package.json b/extensions/chromium/runet-censorship-bypass/package.json index e161dd3..3b69739 100644 --- a/extensions/chromium/runet-censorship-bypass/package.json +++ b/extensions/chromium/runet-censorship-bypass/package.json @@ -3,14 +3,19 @@ "version": "0.0.19", "description": "Development tools for chromium extension", "scripts": { + "postinstall": "node --use_strict -e \"const fs = require('fs'), path = 'node_modules/_project-root'; fs.unlink(path, ()=> fs.symlinkSync('..', path, 'dir'));\"", "lint": "eslint ./src/**/*.js --ignore-pattern vendor", - "gulp": "gulp" + "gulp": "gulp", + "test": "mocha --recursive ./src/**/test/*" }, "author": "Ilya Ig. Petrov", "license": "GPLv3", "devDependencies": { + "chai": "^3.5.0", "eslint": "^3.15.0", - "eslint-config-google": "^0.7.1" + "eslint-config-google": "^0.7.1", + "mocha": "^3.3.0", + "sinon-chrome": "^2.2.1" }, "dependencies": { "del": "^2.2.2", diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js index 1cb6214..d359622 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/00-init-apis.js @@ -125,16 +125,16 @@ key = prefix + key; if (value === null) { - return localStorage.removeItem(key); + return window.localStorage.removeItem(key); } if (value === undefined) { - const item = localStorage.getItem(key); + const item = window.localStorage.getItem(key); return item && JSON.parse(item); } if (value instanceof Date) { throw new TypeError('Converting Date format to JSON is not supported.'); } - localStorage.setItem(key, JSON.stringify(value)); + window.localStorage.setItem(key, JSON.stringify(value)); }; diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js index 33fe42c..214d16a 100644 --- a/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/35-pac-kitchen-api.js @@ -104,7 +104,14 @@ const getCurrentConfigs = function getCurrentConfigs() { - const [err, mods, ...warns] = createPacModifiers( kitchenState(modsKey) ); + const oldMods = kitchenState(modsKey); + if (oldMods) { + // No migration! + return oldMods; + } + + // In case of first install. + const [err, mods, ...warns] = createPacModifiers(); if (err) { throw err; } @@ -148,7 +155,6 @@ }); - console.log('Input mods:', mods); const self = {}; Object.assign(self, getDefaults(), mods); self.ifNoMods = ifNoMods; diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/test/pac-kitchen.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/test/pac-kitchen.js new file mode 100644 index 0000000..1cb7c0b --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/test/pac-kitchen.js @@ -0,0 +1,84 @@ +'use strict'; + +const Storage = require('_project-root/tools/sinon-storage'); +const Chai = require('chai'); +const Mocha = require('mocha'); + +const CachelessRequire = require('_project-root/tools/cacheless-require')(module); + +Mocha.describe('window.apis.pacKitchen', function () { + + Mocha.beforeEach(function() { + + global.chrome = CachelessRequire('sinon-chrome/extensions'); + global.window = { + chrome: global.chrome, + localStorage: new Storage(), + }; + CachelessRequire('../00-init-apis.js'); + + }); + + Mocha.it('is exported with correct default values', function () { + + CachelessRequire('../35-pac-kitchen-api.js'); + Chai.expect(window.apis.pacKitchen, 'to be exported as global').to.exist; + + const mods = window.apis.pacKitchen.getPacMods(); + Chai.expect( + mods, 'to expose default configs on first run' + ).to.exist; + Chai.expect(mods.ifNoMods, 'to impose modifications by default (prohibits DIRECT)').to.be.false; + + const orderedMods = window.apis.pacKitchen.getOrderedConfigs(); + Chai.expect(orderedMods, 'to have method for getting ordered configs').to.exist; + { + const several = 9; + Chai.expect(orderedMods.length, 'to have several ordered configs').to.be.above(several); + } + + Chai.expect( + Object.keys(mods).length, + 'pacModifiers to inherit default configs keys as props and add extra props' + ).to.be.above(orderedMods.length); + + Chai.expect( + orderedMods.every((mod) => mods[mod.key] === mod.dflt), + 'all configs to be default on first run' + ).to.be.ok; + + const excMods = window.apis.pacKitchen.getOrderedConfigs('exceptions'); + Chai.expect(excMods.length, 'to have several ordered mods under category "exceptions"').to.be.above(0); + + const proxyMods = window.apis.pacKitchen.getOrderedConfigs('ownProxies'); + Chai.expect(proxyMods.length, 'to have several ordered mods under category "ownProxies"').to.be.above(0); + + const generalMods = window.apis.pacKitchen.getOrderedConfigs('general'); + Chai.expect(generalMods.length, 'to have several ordered mods without category').to.be.above(0); + + Chai.expect( + orderedMods.length, 'to be a sum of categorized (and ordered) mods' + ).to.be.equal( + proxyMods.length + excMods.length + generalMods.length + ); + + }); + + Mocha.it('is installed (by modifying `chrome.proxy.settings.set`)', function () { + + CachelessRequire('../35-pac-kitchen-api.js'); + Chai.expect(originalSet.notCalled, 'original set not to be called during install').to.be.true; + //Chai.expect(originalSet, 'settings.set to be modified').not.to.be.equal(window.chrome.proxy.settings.set); + + }); + + Mocha.afterEach(function() { + + delete global.window; + + }); + +}); + + + diff --git a/extensions/chromium/runet-censorship-bypass/src/extension-common/test/utils.js b/extensions/chromium/runet-censorship-bypass/src/extension-common/test/utils.js new file mode 100644 index 0000000..afb7341 --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass/src/extension-common/test/utils.js @@ -0,0 +1,35 @@ +'use strict'; + +const Chai = require('chai'); +const Mocha = require('mocha'); + +const CachelessRequire = require('_project-root/tools/cacheless-require')(module); + +Mocha.describe('window.utils', function () { + + const initApis = '../00-init-apis.js'; + + Mocha.beforeEach(function() { + + global.window = {}; + + }); + + Mocha.it('is exported as global', function () { + + CachelessRequire(initApis); + Chai.expect(window.utils, 'to be exported as global').to.exist; + Chai.expect(window.apis.version.ifMini, 'to be marked as not MINI version by default').to.be.false; + + }); + + Mocha.afterEach(function() { + + delete global.window; + + }); + +}); + + + diff --git a/extensions/chromium/runet-censorship-bypass/tools/cacheless-require.js b/extensions/chromium/runet-censorship-bypass/tools/cacheless-require.js new file mode 100644 index 0000000..abdbe13 --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass/tools/cacheless-require.js @@ -0,0 +1,10 @@ +'ust strict'; + +module.exports = (parentModule) => function cachelessRequire(path) { + + for(let key of Object.keys(require.cache)) { + delete require.cache[key]; + } + return parentModule.require(path); + +}; diff --git a/extensions/chromium/runet-censorship-bypass/tools/sinon-storage.js b/extensions/chromium/runet-censorship-bypass/tools/sinon-storage.js new file mode 100644 index 0000000..7a2d356 --- /dev/null +++ b/extensions/chromium/runet-censorship-bypass/tools/sinon-storage.js @@ -0,0 +1,48 @@ +'use strict'; + +const Sinon = require('sinon'); + +module.exports = function storageMock() { + + let storage = {}; + + return new Proxy({ + setItem: Sinon.spy(function(key, value) { + storage[key] = value || ''; + }), + getItem: Sinon.spy(function(key) { + return key in storage ? storage[key] : null; + }), + removeItem: Sinon.spy(function(key) { + delete storage[key]; + }), + get length() { + return Object.keys(storage).length; + }, + key: Sinon.spy(function(i) { + throw new Error('Not implemented!'); + }), + clear: Sinon.spy(function() { + storage = {}; + }), + }, { + get: function(target, name) { + + if (name in target) { + return target[name]; + } + return target.getItem(name); + + }, + set: function(target, prop, value) { + + if (prop in target) { + target[prop] = value; + return; + } + return target.setItem(prop, value); + + }, + }); + +};