diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..08196cd --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,3 @@ +((js-mode . ((indent-tabs-mode . nil) + (js-indent-level . 2) + (js-switch-indent-offset . 2)))) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 68c6d74..6482588 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -45,6 +45,9 @@ jobs: cp webextensions/chrome/manifest.json.dev webextensions/chrome/manifest.json make -C webextensions/chrome make -C webextensions/firefox + - name: Run tests + run: | + make -C webextensions test - name: Upload Extensions uses: actions/upload-artifact@v4 with: @@ -59,6 +62,9 @@ jobs: make -C webextensions/edge make -C webextensions/chrome make -C webextensions/firefox + - name: Run tests + run: | + make -C webextensions test - name: Upload Extensions uses: actions/upload-artifact@v4 with: diff --git a/.gitignore b/.gitignore index d34ddea..268279d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ ipch/ *_i.[ch] *_p.[ch] *.zip +webextensions/testee diff --git a/webextensions/.eslintignore b/webextensions/.eslintignore index 5ed8ed7..becc55f 100644 --- a/webextensions/.eslintignore +++ b/webextensions/.eslintignore @@ -5,3 +5,5 @@ tools/ */dev/ */enterprise-dev/ +testee/ +test/ diff --git a/webextensions/Makefile b/webextensions/Makefile index 8f586b2..b8c2150 100644 --- a/webextensions/Makefile +++ b/webextensions/Makefile @@ -5,11 +5,29 @@ NPM_BIN_DIR := $(NPM_MOD_DIR)/.bin all: packages +testee: + mkdir $@ + +testee/chrome.js: chrome/background.js testee + sed -e "s/Redirector.init();/exports.redirector = Redirector/g" chrome/background.js > $@ + +testee/edge.js: edge/background.js testee + sed -e "s/Redirector.init();/exports.redirector = Redirector/g" edge/background.js > $@ + +unittest: install_dependency testee/chrome.js testee/edge.js + npx mocha --require mocha-suppress-logs test + +test: unittest + +test-verbose: install_dependency testee/chrome.js testee/edge.js + npx mocha test + clean: rm -f *.zip rm -f *.xpi + rm -rf testee -packages: clean lint +packages: test clean lint cd chrome && make && make dev && make enterprise-dev && mv *.zip ../ cd edge && make && make dev && make enterprise-dev && mv *.zip ../ cd firefox && make && mv *.xpi ../ diff --git a/webextensions/chrome/background.js b/webextensions/chrome/background.js index 0a5b2c0..21aaec4 100644 --- a/webextensions/chrome/background.js +++ b/webextensions/chrome/background.js @@ -322,7 +322,7 @@ const Redirector = { } } - for (const [pattern, browser] of Object.entries(config.HostNamePatterns)) { + for (const [pattern, browser] of config.HostNamePatterns) { if (wildmat(host, pattern)) { console.log(`* Match with '${pattern}' (browser=${browser})`); return browser.toLowerCase(); diff --git a/webextensions/edge/background.js b/webextensions/edge/background.js index 95bf248..dc51b6a 100644 --- a/webextensions/edge/background.js +++ b/webextensions/edge/background.js @@ -322,7 +322,7 @@ const Redirector = { } } - for (const [pattern, browser] of Object.entries(config.HostNamePatterns)) { + for (const [pattern, browser] of config.HostNamePatterns) { if (wildmat(host, pattern)) { console.log(`* Match with '${pattern}' (browser=${browser})`); return browser.toLowerCase(); diff --git a/webextensions/package.json b/webextensions/package.json index 1426c9c..7fdd56d 100644 --- a/webextensions/package.json +++ b/webextensions/package.json @@ -20,8 +20,11 @@ "jsonlint-cli": "*", "lodash": ">=4.17.21", "minimist": ">=1.2.2", + "mocha": ">=10.4.0", + "mocha-suppress-logs": "^0.5.1", "morphdom": "^2.5.12", "node-fetch": ">=2.6.1", + "sinon": "^14.0.0", "trim-newlines": ">=3.0.1", "tunnel-agent": ">=0.6.0", "underscore": ">=1.12.1" diff --git a/webextensions/test/chrome-stub.js b/webextensions/test/chrome-stub.js new file mode 100644 index 0000000..be7c62a --- /dev/null +++ b/webextensions/test/chrome-stub.js @@ -0,0 +1,50 @@ +global.chrome = { + alarms: { + create: function() { + }, + onAlarm: { + addListener: function() { + } + }, + }, + runtime: { + sendNativeMessage: function() { + }, + }, + tabs: { + onCreated: { + addListener: function() { + } + }, + onRemoved: { + addListener: function() { + } + }, + onUpdated: { + addListener: function() { + } + }, + }, + windows: { + onCreated: { + addListener: function() { + } + }, + onRemoved: { + addListener: function() { + } + }, + }, + webRequest: { + onBeforeRequest: { + addListener: function() { + }, + }, + }, + webNavigation: { + onCommitted: { + addListener: function() { + } + }, + }, +}; diff --git a/webextensions/test/test-get-host.js b/webextensions/test/test-get-host.js new file mode 100644 index 0000000..64d45cb --- /dev/null +++ b/webextensions/test/test-get-host.js @@ -0,0 +1,33 @@ +const assert = require('assert'); +const chromestub = require('./chrome-stub.js'); + +describe('getHost', () => { + const redirectors = [ + { browser: 'chrome', module: require('../testee/chrome.js') }, + { browser: 'edge', module: require('../testee/edge.js') }, + ].forEach(({browser, module}) => { + describe(browser, () => { + const redirector = module.redirector; + it('http: extract host name', () => { + const url = 'http://www.google.com/'; + assert.equal(redirector._getHost(url), 'www.google.com'); + }); + it('https: extract host name', () => { + const url = 'https://www.google.com/'; + assert.equal(redirector._getHost(url), 'www.google.com'); + }); + it('exclude account', () => { + const url = 'https://foobar:password@www.google.com/'; + assert.equal(redirector._getHost(url), 'www.google.com'); + }); + // TODO: + // Although C++ implementation intends to exclude port number, JavaScript + // one includes it. So that this test always fails with current code. + // We may need to fix it. + it('exclude port number' /*, () => { + const url = 'https://www.google.com:8080/'; + assert.equal(redirector._getHost(url), 'www.google.com'); + }*/); + }); + }); +}); diff --git a/webextensions/test/test-is-redirect-url.js b/webextensions/test/test-is-redirect-url.js new file mode 100644 index 0000000..ca267bb --- /dev/null +++ b/webextensions/test/test-is-redirect-url.js @@ -0,0 +1,65 @@ +const assert = require('assert'); +const chromestub = require('./chrome-stub.js'); + +describe('isRedirectURL', () => { + const redirectors = [ + { browser: 'chrome', module: require('../testee/chrome.js') }, + { browser: 'edge', module: require('../testee/edge.js') }, + ].forEach(({browser, module}) => { + const redirector = module.redirector; + describe(browser, () => { + const baseConfig = { + DefaultBrowser: browser, + SecondBrowser: "", + FirefoxCommannd: "", + CloseEmptyTab: 1, + OnlyOnAnchorClick: 0, + UseRegex: 0, + URLPatterns: [], + HostNamePatterns: [], + ZonePatterns: [], + } + function config(URLPatterns = [], HostNamePatterns = [], additionals = {}) { + const config = {...baseConfig, ...additionals}; + config.URLPatterns = [...config.URLPatterns, ...URLPatterns]; + config.HostNamePatterns = [...config.HostNamePatterns, ...HostNamePatterns]; + return config; + } + describe('Empty redirect pattern', () => { + it(`Should not redirect when default browser is ${browser}`, () => { + const url = 'http://www.google.com/'; + assert.equal(redirector.isRedirectURL(baseConfig, url), false); + }); + it(`Should redirect when default browser is not ${browser}`, () => { + const defaultBrowser = browser === 'edge' ? 'chrome' : 'edge'; + const url = 'http://www.google.com/'; + assert.equal(redirector.isRedirectURL(config([], [], {DefaultBrowser: defaultBrowser}), url), true); + }); + }); + describe('URL patterns', () => { + it(`Match redirect pattern`, () => { + const url = 'http://www.example.com/'; + const conf = config([['http*://*.example.com/*', 'firefox']]) + assert.equal(redirector.isRedirectURL(conf, url), true); + }); + it(`Unmatch redirect pattern`, () => { + const url = 'http://www.google.com/'; + const conf = config([['http*://*.example.com/*', 'firefox']]) + assert.equal(redirector.isRedirectURL(conf, url), false); + }); + }); + describe('HostName patterns', () => { + it(`Match redirect pattern`, () => { + const url = 'http://www.example.com/'; + const conf = config([], [['*.example.com', 'firefox']]) + assert.equal(redirector.isRedirectURL(conf, url), true); + }); + it(`Unmatch redirect pattern`, () => { + const url = 'http://www.google.com/'; + const conf = config([], [['*.example.com', 'firefox']]) + assert.equal(redirector.isRedirectURL(conf, url), false); + }); + }); + }); + }); +});