зеркало из https://github.com/mozilla/kitsune.git
fix tests to work with webpack
run tests through webpack first, then mocha reorganise webpack config files
This commit is contained in:
Родитель
8e66941f01
Коммит
97a7514315
|
@ -39,7 +39,7 @@ jobs:
|
|||
command: ./bin/dc_ci.sh run test ./bin/run-unit-tests.sh
|
||||
- run:
|
||||
name: Run js tests
|
||||
command: ./bin/dc_ci.sh run test ./bin/run-mocha-tests.sh
|
||||
command: ./bin/dc_ci.sh run test npm run webpack:test
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
|
|
|
@ -28,7 +28,7 @@ repos:
|
|||
hooks:
|
||||
- id: eslint
|
||||
args: [--no-eslintrc, --config=webpack/eslintrc.js]
|
||||
exclude: "webpack/.*"
|
||||
exclude: "webpack/.*|webpack\\..*\\.js"
|
||||
additional_dependencies:
|
||||
- eslint@8.1.0
|
||||
- eslint-import-resolver-webpack@0.13.2
|
||||
|
|
2
Makefile
2
Makefile
|
@ -81,7 +81,7 @@ test: .docker-build
|
|||
${DC} run web ./bin/run-unit-tests.sh
|
||||
|
||||
test-js: .docker-build
|
||||
${DC} run web ./bin/run-mocha-tests.sh
|
||||
${DC} run web npm run webpack:test
|
||||
|
||||
docs: .docker-build
|
||||
${DC} run web $(MAKE) -C docs/ clean
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
./node_modules/.bin/mocha --require ./webpack/mocha-require --recursive kitsune/*/static/*/js/tests/* $@
|
|
@ -144,7 +144,7 @@ Running JavaScript Tests
|
|||
To run tests, make sure you have have the NPM dependencies installed, and
|
||||
then run::
|
||||
|
||||
$ bin/run-mocha-tests.sh
|
||||
$ npm run webpack:test
|
||||
|
||||
Writing JavaScript Tests
|
||||
------------------------
|
||||
|
@ -164,7 +164,6 @@ Here are a few tips for writing tests:
|
|||
* You can use `sinon` to mock out parts of libraries or functions under
|
||||
test. This is useful for testing AJAX.
|
||||
* The tests run in a Node.js environment. A browser environment can be
|
||||
simulated using ``jsdom``. Specifically, ``mocha-jsdom`` is useful to
|
||||
set up and tear down the simulated environment.
|
||||
simulated using ``jsdom``.
|
||||
|
||||
.. _Mocha: https://mochajs.org/
|
||||
|
|
|
@ -5,7 +5,7 @@ export default env;
|
|||
|
||||
(function($) {
|
||||
|
||||
env.addGlobal('_', gettext);
|
||||
env.addGlobal('_', window.gettext);
|
||||
env.addGlobal('ngettext', window.ngettext);
|
||||
|
||||
env.addFilter('f', function(fmt, obj, named) {
|
||||
|
@ -16,7 +16,7 @@ export default env;
|
|||
obj[keys[i]] = escape(obj[keys[i]]);
|
||||
}
|
||||
|
||||
return interpolate(fmt, obj, named);
|
||||
return window.interpolate(fmt, obj, named);
|
||||
});
|
||||
|
||||
env.addFilter('urlparams', function(url, params) {
|
||||
|
|
|
@ -17,8 +17,6 @@ import AAQSystemInfo from "sumo/js/aaq";
|
|||
// TODO: Figure out how to break out the functionality here into
|
||||
// testable parts.
|
||||
|
||||
(function($) {
|
||||
|
||||
function init() {
|
||||
var $body = $('body');
|
||||
|
||||
|
@ -278,7 +276,7 @@ import AAQSystemInfo from "sumo/js/aaq";
|
|||
/*
|
||||
* Links all crash IDs found in the passed HTML container elements
|
||||
*/
|
||||
function linkCrashIds(container) {
|
||||
export function linkCrashIds(container) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
@ -325,5 +323,3 @@ import AAQSystemInfo from "sumo/js/aaq";
|
|||
}
|
||||
|
||||
$(document).ready(init);
|
||||
|
||||
})(jQuery);
|
||||
|
|
|
@ -345,9 +345,9 @@ ShowFor.prototype.initShowFuncs = function() {
|
|||
ShowFor.prototype.showAndHide = function() {
|
||||
this.$container.find('.for').each(function(i, elem) {
|
||||
var $elem = $(elem);
|
||||
var showFunc = $elem.data('show-func');
|
||||
if (showFunc) {
|
||||
$elem.toggle(showFunc());
|
||||
var showFuncVal = $elem.data('show-func')();
|
||||
if (showFuncVal !== undefined) {
|
||||
$elem.toggle(showFuncVal);
|
||||
} else {
|
||||
$elem.show();
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ import _keys from "underscore/modules/keys";
|
|||
* A tag filtering form.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
function init($container) {
|
||||
var $form = $container ? $container.find('form') : $('#tag-filter form'),
|
||||
$tags = $form.find('input[type="text"]'), $btn = $form.find('input[type="submit"], button'),
|
||||
|
@ -90,9 +88,8 @@ import _keys from "underscore/modules/keys";
|
|||
const TagsFilter = {
|
||||
init: init
|
||||
};
|
||||
export default TagsFilter;
|
||||
|
||||
$(document).ready(function() {
|
||||
TagsFilter.init();
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
|
|
@ -1,28 +1,13 @@
|
|||
import React from 'react';
|
||||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {expect} from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import mochaGettext from './fixtures/mochaGettext.js';
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
|
||||
import AjaxPreview from "sumo/js/ajaxpreview";
|
||||
|
||||
describe('ajax preview', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
mochaGettext();
|
||||
/* globals window, $, k */
|
||||
|
||||
var fakeServer;
|
||||
|
||||
describe('events', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../ajaxpreview.js');
|
||||
rerequire('../libs/jquery.lazyload.js');
|
||||
|
||||
sinon.stub($, 'ajax').yieldsTo('success', '<p>The content to preview.</p>');
|
||||
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
import React from 'react';
|
||||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {expect} from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
|
||||
import AjaxVote from "sumo/js/ajaxvote";
|
||||
|
||||
describe('ajaxvote', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
/* globals window, document, $, k */
|
||||
|
||||
describe('helpful vote', () => {
|
||||
let fakeServer;
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../ajaxvote.js');
|
||||
|
||||
sinon.stub($, 'ajax').yieldsTo('success', {message: 'Thanks for the vote!'});
|
||||
|
||||
let sandbox = (
|
||||
|
@ -34,6 +21,7 @@ describe('ajaxvote', () => {
|
|||
afterEach(() => {
|
||||
$.ajax.restore();
|
||||
React.unmountComponentAtNode(document.body);
|
||||
$(document).off('vote');
|
||||
});
|
||||
|
||||
it('should fire an event on a helpful vote', done => {
|
||||
|
|
|
@ -1,21 +1,8 @@
|
|||
import {expect} from 'chai';
|
||||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
|
||||
import mochaUnderscore from './fixtures/mochaUnderscore.js';
|
||||
import BrowserDetect from "sumo/js/browserdetect";
|
||||
|
||||
describe('BrowserDetect', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaUnderscore();
|
||||
/* globals window */
|
||||
|
||||
let BrowserDetect;
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../browserdetect.js');
|
||||
|
||||
BrowserDetect = window.BrowserDetect;
|
||||
});
|
||||
|
||||
describe('Fennec versions', () => {
|
||||
it('should detect Fennec 7', () => {
|
||||
let ua = 'Mozilla/5.0 (Android; Linux armv7l; rv:7.0.1) Gecko/ Firefox/7.0.1 Fennec/7.0.1';
|
||||
|
|
|
@ -1,51 +1,37 @@
|
|||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {default as chai, expect} from 'chai';
|
||||
import chaiLint from 'chai-lint';
|
||||
import sinon from 'sinon';
|
||||
import sinonChai from 'sinon-chai';
|
||||
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
import mochaUnderscore from './fixtures/mochaUnderscore.js';
|
||||
import {
|
||||
getQueryParamsAsDict,
|
||||
getReferrer,
|
||||
getSearchQuery,
|
||||
unquote,
|
||||
safeString,
|
||||
safeInterpolate,
|
||||
} from "sumo/js/main";
|
||||
|
||||
chai.use(chaiLint);
|
||||
chai.use(sinonChai);
|
||||
|
||||
describe('k', () => {
|
||||
mochaJsdom({
|
||||
useEach: true,
|
||||
url: 'http://localhost',
|
||||
document: {
|
||||
referrer: 'http://google.com/?q=cookies',
|
||||
referer: 'http://google.com/?q=cookies',
|
||||
},
|
||||
});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
mochaUnderscore();
|
||||
/* globals document:false, $:false, k:false */
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../libs/jquery.placeholder.js');
|
||||
rerequire('../main.js');
|
||||
});
|
||||
|
||||
describe('getQueryParamsAsDict', () => {
|
||||
it('should return an empty object for no params', () => {
|
||||
let url = 'http://example.com';
|
||||
let params = k.getQueryParamsAsDict(url);
|
||||
let params = getQueryParamsAsDict(url);
|
||||
expect(params).to.deep.equal({});
|
||||
});
|
||||
|
||||
it('should parse a query string with one parameter', () => {
|
||||
let url = 'http://example.com/?test=woot';
|
||||
let params = k.getQueryParamsAsDict(url);
|
||||
let params = getQueryParamsAsDict(url);
|
||||
expect(params).to.deep.equal({test: 'woot'});
|
||||
});
|
||||
|
||||
it('should parse a query string with two paramaters', () => {
|
||||
let url = 'http://example.com/?x=foo&y=bar';
|
||||
let params = k.getQueryParamsAsDict(url);
|
||||
let params = getQueryParamsAsDict(url);
|
||||
expect(params).to.deep.equal({x: 'foo', y: 'bar'});
|
||||
});
|
||||
|
||||
|
@ -54,7 +40,7 @@ describe('k', () => {
|
|||
'ved=0CDEQFjAA&url=http%3A%2F%2Fsupport.mozilla.com%2F&' +
|
||||
'rct=j&q=firefox%20help&ei=OsBSTpbZBIGtgQfgzv3yBg&' +
|
||||
'usg=AFQjCNFIV7wgd9Pnr0m3Ofc7r1zVTNK8dw');
|
||||
let params = k.getQueryParamsAsDict(url);
|
||||
let params = getQueryParamsAsDict(url);
|
||||
expect(params).to.deep.equal({
|
||||
sa: 't',
|
||||
source: 'web',
|
||||
|
@ -70,50 +56,23 @@ describe('k', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('queryParamStringFromDict', () => {
|
||||
it('should serialize an empty dict into a ?', () => {
|
||||
let actual = k.queryParamStringFromDict({});
|
||||
expect(actual).to.equal('?');
|
||||
});
|
||||
|
||||
it('it should serialize an object with a single key', () => {
|
||||
let actual = k.queryParamStringFromDict({foo: 1});
|
||||
expect(actual).to.equal('?foo=1');
|
||||
});
|
||||
|
||||
it('should serialize an object with two keys', () => {
|
||||
let actual = k.queryParamStringFromDict({foo: 1, bar: 2});
|
||||
expect(actual).to.equal('?foo=1&bar=2');
|
||||
});
|
||||
|
||||
it('should not include null or undefined in the output', () => {
|
||||
let actual = k.queryParamStringFromDict({foo: undefined, bar: 2, baz: null});
|
||||
expect(actual).to.equal('?bar=2');
|
||||
});
|
||||
|
||||
it('should serialize an object with three keys', () => {
|
||||
let actual = k.queryParamStringFromDict({foo: 1, bar: 2, baz: 3});
|
||||
expect(actual).to.deep.equal('?foo=1&bar=2&baz=3');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getReferrer', () => {
|
||||
it('should recognize search referrers', () => {
|
||||
let params = {as: 's', s: 'cookies'};
|
||||
let actual = k.getReferrer(params);
|
||||
let actual = getReferrer(params);
|
||||
expect(actual).to.equal('search');
|
||||
});
|
||||
|
||||
it('should recognize inproduct referrers', () => {
|
||||
let params = {as: 'u'};
|
||||
let actual = k.getReferrer(params);
|
||||
let actual = getReferrer(params);
|
||||
expect(actual).to.equal('inproduct');
|
||||
});
|
||||
|
||||
it('should fall back to `document.referrer`', () => {
|
||||
let referrer = 'http://google.com/?q=cookies';
|
||||
expect(document.referrer).to.equal(referrer);
|
||||
expect(k.getReferrer({})).to.equal(referrer);
|
||||
expect(getReferrer({})).to.equal(referrer);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -121,54 +80,54 @@ describe('k', () => {
|
|||
it('should return the s query string for local search referrers', () => {
|
||||
let params = {as: 's', s: 'cookies'};
|
||||
let referrer = 'search';
|
||||
expect(k.getSearchQuery(params, referrer)).to.equal('cookies');
|
||||
expect(getSearchQuery(params, referrer)).to.equal('cookies');
|
||||
});
|
||||
|
||||
it('should return an empty string fro inproduct referrers', () => {
|
||||
let params = {as: 'u', s: 'wrong'};
|
||||
let referrer = 'inproduct';
|
||||
expect(k.getSearchQuery(params, referrer)).to.equal('');
|
||||
expect(getSearchQuery(params, referrer)).to.equal('');
|
||||
});
|
||||
|
||||
it('should detect external search parameters from google', () => {
|
||||
let referrer = 'http://google.com/?q=cookies';
|
||||
expect(k.getSearchQuery({}, referrer)).to.equal('cookies');
|
||||
expect(getSearchQuery({}, referrer)).to.equal('cookies');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unquote', () => {
|
||||
it('should return undefined for undefined input', () => {
|
||||
expect(k.unquote(undefined)).to.beUndefined();
|
||||
expect(unquote(undefined)).to.beUndefined();
|
||||
});
|
||||
|
||||
it('should unquote simply quoted strings', () => {
|
||||
expect(k.unquote('"delete cookies"')).to.equal('delete cookies');
|
||||
expect(unquote('"delete cookies"')).to.equal('delete cookies');
|
||||
});
|
||||
|
||||
it('should handle escaped quotes', () => {
|
||||
expect(k.unquote('"\\"delete\\" cookies"')).to.equal('"delete" cookies');
|
||||
expect(unquote('"\\"delete\\" cookies"')).to.equal('"delete" cookies');
|
||||
});
|
||||
|
||||
it('should handle escaped quotes with no other quotes', () => {
|
||||
expect(k.unquote('\\"delete\\" cookies')).to.equal('"delete" cookies');
|
||||
expect(unquote('\\"delete\\" cookies')).to.equal('"delete" cookies');
|
||||
});
|
||||
|
||||
it('should pass strings without quotes through unmodified', () => {
|
||||
let s = 'cookies';
|
||||
expect(k.unquote(s)).to.equal(s);
|
||||
expect(unquote(s)).to.equal(s);
|
||||
});
|
||||
});
|
||||
|
||||
describe('safeString', () => {
|
||||
it('should escape html', function() {
|
||||
let unsafeString = '<a href="foo&\'">';
|
||||
let safeString = '<a href="foo&'">';
|
||||
expect(k.safeString(unsafeString)).to.equal(safeString);
|
||||
let expectedString = '<a href="foo&'">';
|
||||
expect(safeString(unsafeString)).to.equal(expectedString);
|
||||
});
|
||||
});
|
||||
|
||||
describe('safeInterpolate', () => {
|
||||
/* k.safeInterpolate works by delegating to `interpolate`, a Django
|
||||
/* safeInterpolate works by delegating to `interpolate`, a Django
|
||||
* gettext function. These tests mock out interpolate and make sure
|
||||
* it was called appropriately.
|
||||
*/
|
||||
|
@ -183,7 +142,7 @@ describe('k', () => {
|
|||
let unsafe = ['<a>', '<script>'];
|
||||
let safe = ['<a>', '<script>'];
|
||||
|
||||
k.safeInterpolate(html, unsafe, false);
|
||||
safeInterpolate(html, unsafe, false);
|
||||
|
||||
expect(interpolateSpy).to.have.callCount(1);
|
||||
expect(interpolateSpy).to.have.been.calledWithExactly(html, safe, false);
|
||||
|
@ -199,7 +158,7 @@ describe('k', () => {
|
|||
display: '<script>alert('xss');</script>',
|
||||
name: 'Jo&mdash;hn',
|
||||
};
|
||||
k.safeInterpolate(html, unsafe, true);
|
||||
safeInterpolate(html, unsafe, true);
|
||||
|
||||
expect(interpolateSpy).to.have.callCount(1);
|
||||
expect(interpolateSpy).to.have.been.calledWithExactly(html, safe, true);
|
||||
|
|
|
@ -1,26 +1,10 @@
|
|||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {expect} from 'chai';
|
||||
import React from 'react';
|
||||
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
import mochaGettext from './fixtures/mochaGettext.js';
|
||||
import mochaMarky from './fixtures/mochaMarky.js';
|
||||
import { linkCrashIds } from "sumo/js/questions";
|
||||
|
||||
describe('k', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
mochaGettext();
|
||||
mochaMarky();
|
||||
/* globals window, document, $, k */
|
||||
|
||||
describe('linkCrashIds', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../questions.js');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
React.unmountComponentAtNode(document.body);
|
||||
});
|
||||
|
@ -39,7 +23,7 @@ describe('k', () => {
|
|||
);
|
||||
React.render(sandbox, document.body);
|
||||
|
||||
k.linkCrashIds($('body'));
|
||||
linkCrashIds($('body'));
|
||||
expect($('.crash-report').length).to.equal(1);
|
||||
});
|
||||
|
||||
|
@ -61,7 +45,7 @@ describe('k', () => {
|
|||
);
|
||||
React.render(sandbox, document.body);
|
||||
|
||||
k.linkCrashIds($('body'));
|
||||
linkCrashIds($('body'));
|
||||
expect($('.crash-report').length).to.equal(5);
|
||||
});
|
||||
|
||||
|
@ -73,7 +57,7 @@ describe('k', () => {
|
|||
</section>
|
||||
);
|
||||
React.render(sandbox, document.body);
|
||||
k.linkCrashIds($('body'));
|
||||
linkCrashIds($('body'));
|
||||
|
||||
expect($('.crash-report').length).to.equal(0);
|
||||
});
|
||||
|
@ -87,7 +71,7 @@ describe('k', () => {
|
|||
);
|
||||
React.render(sandbox, document.body);
|
||||
|
||||
k.linkCrashIds($('body'));
|
||||
linkCrashIds($('body'));
|
||||
expect($('.crash-report').length).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
|
||||
export default mochaFixtureHelper(({browser='firefox', version=25.0, OS='winxp'}={}) => {
|
||||
let BrowserDetect = {browser, version, OS};
|
||||
return {
|
||||
BrowserDetect: BrowserDetect,
|
||||
};
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* Install globals into the jsdom namespace.
|
||||
* @param {function} mapFunc This function will be called to get the list of
|
||||
* things to install into the namespace. Should return an object of keys
|
||||
* to values to install.
|
||||
*/
|
||||
export default function(mapFunc) {
|
||||
return function(options) {
|
||||
let map;
|
||||
|
||||
global.beforeEach(() => {
|
||||
map = mapFunc(options);
|
||||
for (let key in map) {
|
||||
let val = map[key];
|
||||
global[key] = val;
|
||||
if (global.window) {
|
||||
global.window[key] = val;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
global.afterEach(() => {
|
||||
for (let key in map) {
|
||||
delete global[key];
|
||||
if (global.window) {
|
||||
delete global.window[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
|
||||
function fakeGettext(msgid) {
|
||||
return msgid;
|
||||
}
|
||||
|
||||
export default mochaFixtureHelper(() => {
|
||||
return {
|
||||
gettext: fakeGettext,
|
||||
};
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
|
||||
export default mochaFixtureHelper(() => {
|
||||
return {
|
||||
_gaq: [],
|
||||
trackEvent: function() {}
|
||||
};
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
import jQuery from 'jquery';
|
||||
|
||||
export default mochaFixtureHelper(() => {
|
||||
let jq = jQuery(global.window);
|
||||
return {
|
||||
$: jq,
|
||||
jQuery: jq,
|
||||
};
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
|
||||
export default mochaFixtureHelper(() => {
|
||||
let k = global.k || (global.window ? global.window.k : null) || {};
|
||||
return {
|
||||
k: k,
|
||||
};
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
import {rerequire} from 'mocha-jsdom';
|
||||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
|
||||
export default mochaFixtureHelper(() => {
|
||||
rerequire('../../markup.js');
|
||||
return {
|
||||
Marky: global.window.Marky,
|
||||
};
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
import path from 'path';
|
||||
import {rerequire} from 'mocha-jsdom';
|
||||
import {FileSystemLoader} from 'nunjucks';
|
||||
|
||||
/**
|
||||
* Load and set up nunjucks and the Sumo nunjucks environment for Mocha tests.
|
||||
*/
|
||||
export default function() {
|
||||
global.beforeEach(() => {
|
||||
let nunjucks = rerequire('nunjucks');
|
||||
|
||||
global.nunjucks = nunjucks;
|
||||
if (global.window) {
|
||||
global.window.nunjucks = nunjucks;
|
||||
}
|
||||
|
||||
const originalConfigure = nunjucks.configure;
|
||||
nunjucks.configure = opts => {
|
||||
opts.watch = false;
|
||||
return originalConfigure(opts);
|
||||
};
|
||||
|
||||
rerequire('../../nunjucks.js');
|
||||
global.window.k.nunjucksEnv.loaders = [
|
||||
new FileSystemLoader('kitsune/sumo/static/sumo/tpl', true, true)
|
||||
];
|
||||
global.window.k.nunjucksEnv.initCache();
|
||||
});
|
||||
|
||||
global.afterEach(() => {
|
||||
delete global.nunjucks;
|
||||
delete global.nunjucksEnv;
|
||||
if (global.window) {
|
||||
delete global.window.nunjucks;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import mochaFixtureHelper from './mochaFixtureHelper.js';
|
||||
import _ from 'underscore';
|
||||
|
||||
export default mochaFixtureHelper(() => {
|
||||
return {
|
||||
_: _,
|
||||
};
|
||||
});
|
|
@ -1,48 +1,23 @@
|
|||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {default as chai, expect} from 'chai';
|
||||
import React from 'react';
|
||||
import chaiLint from 'chai-lint';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
import mochaGoogleAnalytics from './fixtures/mochaGoogleAnalytics.js';
|
||||
import mochaNunjucks from './fixtures/mochaNunjucks.js';
|
||||
import mochaGettext from './fixtures/mochaGettext.js';
|
||||
import "sumo/js/templates/search-results";
|
||||
import "sumo/js/instant_search";
|
||||
import CachedXHR from "sumo/js/cached_xhr";
|
||||
|
||||
chai.use(chaiLint);
|
||||
|
||||
describe('instant search', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
mochaGoogleAnalytics();
|
||||
mochaGettext();
|
||||
mochaNunjucks();
|
||||
/* globals window, document, $ */
|
||||
|
||||
describe('', () => {
|
||||
let $sandbox;
|
||||
let clock;
|
||||
let cxhrMock;
|
||||
|
||||
beforeEach(() => {
|
||||
clock = sinon.useFakeTimers();
|
||||
window.matchMedia = () => {
|
||||
return {
|
||||
matches: false,
|
||||
addListener: () => {}
|
||||
}
|
||||
}
|
||||
|
||||
global.matchMedia = window.matchMedia;
|
||||
window.Mzp = {};
|
||||
window._localStorage = { getItem: () => undefined };
|
||||
|
||||
rerequire('../i18n.js');
|
||||
global.interpolate = global.window.interpolate;
|
||||
rerequire('../search_utils.js');
|
||||
rerequire('../instant_search.js');
|
||||
|
||||
cxhrMock = sinon.fake();
|
||||
sinon.replace(CachedXHR.prototype, "request", cxhrMock);
|
||||
let content = (
|
||||
<div>
|
||||
<div id="main-content"/>
|
||||
|
@ -58,6 +33,7 @@ describe('instant search', () => {
|
|||
afterEach(() => {
|
||||
React.unmountComponentAtNode(document.body);
|
||||
clock.restore();
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('shows and hides the main content correctly', () => {
|
||||
|
@ -65,27 +41,24 @@ describe('instant search', () => {
|
|||
expect($('#main-content').css('display')).to.not.equal('none');
|
||||
|
||||
$searchInput.val('test');
|
||||
$searchInput.keyup();
|
||||
$searchInput.trigger('keyup');
|
||||
expect($('#main-content').css('display')).to.equal('none');
|
||||
|
||||
$searchInput.val('');
|
||||
$searchInput.keyup();
|
||||
$searchInput.trigger('keyup');
|
||||
expect($('#main-content').css('display')).to.not.equal('none');
|
||||
});
|
||||
|
||||
it('shows the search query at the top of the page', () => {
|
||||
const query = 'search query';
|
||||
const requestExpectation = cxhrMock.expects('request')
|
||||
.once()
|
||||
.withArgs(sinon.match.string, sinon.match(opts => opts.data.q === query));
|
||||
|
||||
const $searchInput = $('#search-q');
|
||||
$searchInput.val(query);
|
||||
$searchInput.keyup();
|
||||
$searchInput.trigger('keyup');
|
||||
|
||||
clock.tick(200);
|
||||
// call the callback to actually render things
|
||||
requestExpectation.firstCall.args[1].success({
|
||||
cxhrMock.firstCall.args[1].success({
|
||||
num_results: 0,
|
||||
q: query,
|
||||
});
|
||||
|
@ -96,15 +69,14 @@ describe('instant search', () => {
|
|||
|
||||
it('escapes the search query at the top of the page', () => {
|
||||
const query = '<';
|
||||
const requestExpectation = cxhrMock.expects('request');
|
||||
|
||||
const $searchInput = $('#search-q');
|
||||
$searchInput.val(query);
|
||||
$searchInput.keyup();
|
||||
$searchInput.trigger('keyup');
|
||||
|
||||
clock.tick(200);
|
||||
// call the callback to actually render things
|
||||
requestExpectation.firstCall.args[1].success({
|
||||
cxhrMock.firstCall.args[1].success({
|
||||
num_results: 0,
|
||||
q: query,
|
||||
});
|
||||
|
|
|
@ -1,31 +1,16 @@
|
|||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {default as chai, expect} from 'chai';
|
||||
import React from 'react';
|
||||
import chaiLint from 'chai-lint';
|
||||
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
import mochaGettext from './fixtures/mochaGettext.js';
|
||||
import mochaMarky from './fixtures/mochaMarky.js';
|
||||
|
||||
import KBox from "sumo/js/kbox.js";
|
||||
|
||||
chai.use(chaiLint);
|
||||
|
||||
describe('kbox', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
mochaGettext();
|
||||
mochaMarky();
|
||||
/* globals window, document, $ */
|
||||
|
||||
describe('declarative', () => {
|
||||
let $kbox, kbox;
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../kbox.js');
|
||||
|
||||
let sandbox = (
|
||||
<div id="sandbox">
|
||||
<div className="kbox"
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {default as chai, expect} from 'chai';
|
||||
import React from 'react';
|
||||
import chaiLint from 'chai-lint';
|
||||
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
|
||||
chai.use(chaiLint);
|
||||
|
||||
describe('lazyload', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
/* globals document, $ */
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../libs/jquery.lazyload.js');
|
||||
});
|
||||
|
||||
it('should load original image', () => {
|
||||
let img = <img className="lazy" data-original-src="http://example.com/test.jpg"/>;
|
||||
React.render(img, document.body);
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React from 'react';
|
||||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {default as chai, expect} from 'chai';
|
||||
import chaiLint from 'chai-lint';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
import mochaBrowserDetect from './fixtures/mochaBrowserDetect.js';
|
||||
import BrowserDetect from 'sumo/js/browserdetect';
|
||||
import ShowFor from "sumo/js/showfor";
|
||||
|
||||
chai.use(chaiLint);
|
||||
|
||||
|
@ -15,7 +14,7 @@ chai.use(chaiLint);
|
|||
* be bound to the passed $sandbox.
|
||||
*/
|
||||
function showForNoInit($sandbox) {
|
||||
let sf = Object.create(window.ShowFor.prototype);
|
||||
let sf = Object.create(ShowFor.prototype);
|
||||
sf.$container = $sandbox;
|
||||
sf.state = {};
|
||||
return sf;
|
||||
|
@ -29,14 +28,9 @@ function unorderedEquals(arr1, arr2) {
|
|||
|
||||
|
||||
describe('ShowFor', () => {
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
/* globals window, document, $ */
|
||||
let showFor;
|
||||
|
||||
beforeEach(() => {
|
||||
rerequire('../showfor.js');
|
||||
|
||||
// Wow. That's a lot of data. Can we make this smaller?
|
||||
let sandbox = (
|
||||
<div>
|
||||
|
@ -124,6 +118,14 @@ describe('ShowFor', () => {
|
|||
|
||||
React.render(sandbox, document.body);
|
||||
showFor = showForNoInit($('body'));
|
||||
|
||||
BrowserDetect.browser = "firefox";
|
||||
BrowserDetect.version = 25.0;
|
||||
BrowserDetect.OS = "winxp";
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
BrowserDetect.init();
|
||||
});
|
||||
|
||||
describe('loadData', () => {
|
||||
|
@ -145,13 +147,10 @@ describe('ShowFor', () => {
|
|||
|
||||
describe('updateUI', () => {
|
||||
describe('Firefox 26 on Windows XP', () => {
|
||||
mochaBrowserDetect({
|
||||
browser: 'fx',
|
||||
version: 26.0,
|
||||
OS: 'winxp',
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
BrowserDetect.browser = "fx"
|
||||
BrowserDetect.version = 26.0
|
||||
BrowserDetect.OS = "winxp"
|
||||
showFor.loadData();
|
||||
showFor.updateUI();
|
||||
});
|
||||
|
@ -163,13 +162,10 @@ describe('ShowFor', () => {
|
|||
});
|
||||
|
||||
describe('Firefox for Android 23', () => {
|
||||
mochaBrowserDetect({
|
||||
browser: 'm',
|
||||
version: 23.0,
|
||||
OS: 'android',
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
BrowserDetect.browser = "m"
|
||||
BrowserDetect.version = 23.0
|
||||
BrowserDetect.OS = "android"
|
||||
showFor.loadData();
|
||||
showFor.updateUI();
|
||||
});
|
||||
|
@ -182,7 +178,6 @@ describe('ShowFor', () => {
|
|||
});
|
||||
|
||||
describe('updateState', () => {
|
||||
mochaBrowserDetect();
|
||||
|
||||
beforeEach(() => {
|
||||
showFor.loadData();
|
||||
|
@ -242,7 +237,6 @@ describe('ShowFor', () => {
|
|||
});
|
||||
|
||||
describe('initShowFuncs', () => {
|
||||
mochaBrowserDetect();
|
||||
|
||||
beforeEach(() => {
|
||||
sinon.stub(showFor, 'matchesCriteria');
|
||||
|
@ -274,7 +268,6 @@ describe('ShowFor', () => {
|
|||
});
|
||||
|
||||
describe('showAndHide', () => {
|
||||
mochaBrowserDetect();
|
||||
|
||||
beforeEach(() => {
|
||||
showFor.loadData();
|
||||
|
@ -302,7 +295,6 @@ describe('ShowFor', () => {
|
|||
});
|
||||
|
||||
describe('matchesCriteria', () => {
|
||||
mochaBrowserDetect();
|
||||
|
||||
beforeEach(() => {
|
||||
showFor.loadData();
|
||||
|
|
|
@ -1,26 +1,11 @@
|
|||
import React from 'react';
|
||||
import {default as mochaJsdom, rerequire} from 'mocha-jsdom';
|
||||
import {expect} from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import mochaGettext from './fixtures/mochaGettext.js';
|
||||
import mochaK from './fixtures/mochaK.js';
|
||||
import mochaJquery from './fixtures/mochaJquery.js';
|
||||
import mochaUnderscore from './fixtures/mochaUnderscore.js';
|
||||
import TagsFilter from "sumo/js/tags.filter";
|
||||
|
||||
describe('k', () => {
|
||||
let form;
|
||||
|
||||
mochaJsdom({useEach: true, url: 'http://localhost'});
|
||||
mochaJquery();
|
||||
mochaK();
|
||||
mochaUnderscore();
|
||||
/* globals window, $, k */
|
||||
|
||||
describe('TagsFilter', () => {
|
||||
beforeEach(() => {
|
||||
rerequire('../tags.filter.js');
|
||||
|
||||
let sandbox = (
|
||||
<div>
|
||||
<section className="tag-filter">
|
||||
|
@ -41,7 +26,7 @@ describe('k', () => {
|
|||
);
|
||||
React.render(sandbox, window.document.body);
|
||||
|
||||
k.TagsFilter.init($('body'));
|
||||
TagsFilter.init($('body'));
|
||||
// Don't let forms submit
|
||||
$('form').submit((e) => e.preventDefault());
|
||||
});
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
19
package.json
19
package.json
|
@ -32,9 +32,10 @@
|
|||
"browser-sync:docs": "browser-sync start --no-open --serveStatic \"styleguide/build\" --files \"styleguide/build/**/*\" --port 4000 --reload-delay=300",
|
||||
"start": "concurrently --raw --kill-others \"npm run webpack:watch\" \"npm run browser-sync\"",
|
||||
"lint:webpack": "npx eslint --no-eslintrc -c webpack/eslintrc.js kitsune",
|
||||
"webpack:build": "npx webpack build --mode development",
|
||||
"webpack:build:prod": "npx webpack build --mode production",
|
||||
"webpack:watch": "npx webpack watch --mode development"
|
||||
"webpack:build": "npx webpack build --config webpack.dev.js",
|
||||
"webpack:build:prod": "npx webpack build --config webpack.prod.js",
|
||||
"webpack:watch": "npx webpack watch --config webpack.dev.js",
|
||||
"webpack:test": "npx webpack build --config webpack.test.js && npx mocha --require ./webpack/mocha-require dist/tests.js"
|
||||
},
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
|
@ -46,7 +47,7 @@
|
|||
"fontawesome": "^4.3.0",
|
||||
"jquery": "1.11.3",
|
||||
"jquery-ui": "1.12.1",
|
||||
"nunjucks": "^1.3.4",
|
||||
"nunjucks": "^3.2.3",
|
||||
"react": "0.13.3",
|
||||
"underscore": "^1.13.1"
|
||||
},
|
||||
|
@ -74,17 +75,17 @@
|
|||
"eslint-plugin-import": "^2.25.2",
|
||||
"exports-loader": "^3.0.0",
|
||||
"expose-loader": "^3.0.0",
|
||||
"glob": "^7.2.0",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"image-minimizer-webpack-plugin": "^2.2.0",
|
||||
"imagemin-optipng": "^8.0.0",
|
||||
"imagemin-svgo": "^9.0.0",
|
||||
"imports-loader": "^3.0.0",
|
||||
"jsdom": "^19.0.0",
|
||||
"kss": "^3.0.0-beta.25",
|
||||
"locutus": "^2.0.15",
|
||||
"mini-css-extract-plugin": "^1.6.0",
|
||||
"mocha": "2.3.2",
|
||||
"mocha-jsdom": "^2.0.0",
|
||||
"nunjucks": "^1.3.4",
|
||||
"onchange": "^6.1.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"postcss": "^8.3.5",
|
||||
|
@ -92,8 +93,9 @@
|
|||
"postcss-loader": "^6.1.1",
|
||||
"sass": "^1.23.2",
|
||||
"sass-loader": "^12.0.0",
|
||||
"sinon": "1.16.1",
|
||||
"sinon": "12.0.1",
|
||||
"sinon-chai": "2.8.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"style-loader": "^2.0.0",
|
||||
"stylelint": "^11.1.1",
|
||||
"stylelint-config-recommended-scss": "^3.3.0",
|
||||
|
@ -102,6 +104,7 @@
|
|||
"svgo": "^1.3.2",
|
||||
"webpack": "^5.38.1",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"webpack-cli": "^4.7.2"
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-merge": "^5.8.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
const webpack = require("webpack");
|
||||
const path = require("path");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
resolve: {
|
||||
alias: {
|
||||
protocol: "@mozilla-protocol/core/protocol",
|
||||
sumo: path.resolve(__dirname, "kitsune/sumo/static/sumo"),
|
||||
community: path.resolve(__dirname, "kitsune/community/static/community"),
|
||||
kpi: path.resolve(__dirname, "kitsune/kpi/static/kpi"),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
"css-loader",
|
||||
"postcss-loader",
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(svg|png|gif|woff2?)$/,
|
||||
type: "asset/resource",
|
||||
},
|
||||
// we copy these libraries from external sources, so define their exports here,
|
||||
// rather than having to modify them, making updating them more difficult:
|
||||
exports(
|
||||
"./kitsune/sumo/static/sumo/js/libs/dnt-helper.js",
|
||||
"default Mozilla.dntEnabled"
|
||||
),
|
||||
exports(
|
||||
"./kitsune/sumo/static/sumo/js/libs/uitour.js",
|
||||
"default Mozilla.UITour"
|
||||
),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
$: "jquery",
|
||||
jQuery: "jquery",
|
||||
"window.jQuery": "jquery",
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
}),
|
||||
],
|
||||
cache: {
|
||||
type: "filesystem",
|
||||
},
|
||||
devtool: "cheap-module-source-map",
|
||||
output: {
|
||||
filename: "[name].js",
|
||||
},
|
||||
};
|
||||
|
||||
function exports(path, exports) {
|
||||
// export the named variable
|
||||
return {
|
||||
test: require.resolve(path),
|
||||
loader: "exports-loader",
|
||||
options: {
|
||||
type: "module",
|
||||
exports,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
const webpack = require("webpack");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
|
||||
const AssetJsonPlugin = require("./webpack/asset-json-plugin");
|
||||
|
||||
const aliases = require("./webpack/aliases");
|
||||
const entrypoints = require("./webpack/entrypoints");
|
||||
const entrypointsHtml = require("./webpack/entrypoints-html");
|
||||
const exportRules = require("./webpack/export-rules");
|
||||
|
||||
const assetModuleFilename = "[name].[contenthash][ext]";
|
||||
|
||||
module.exports = (env, argv) => {
|
||||
const dev = argv.mode === "development";
|
||||
const config = {
|
||||
resolve: {
|
||||
alias: aliases,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
"css-loader",
|
||||
"postcss-loader",
|
||||
"sass-loader",
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(svg|png|gif|woff2?)$/,
|
||||
type: "asset/resource",
|
||||
},
|
||||
...exportRules,
|
||||
],
|
||||
},
|
||||
entry: entrypoints,
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
$: "jquery",
|
||||
jQuery: "jquery",
|
||||
"window.jQuery": "jquery",
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: dev ? "[name].css" : "[name].[contenthash].css",
|
||||
}),
|
||||
...entrypointsHtml,
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: "node_modules/@mozilla-protocol/core/protocol/img/icons/**", to: assetModuleFilename },
|
||||
{ from: "kitsune/*/static/**/img/**", to: assetModuleFilename },
|
||||
],
|
||||
}),
|
||||
new ImageMinimizerPlugin({
|
||||
minimizerOptions: {
|
||||
plugins: [
|
||||
"optipng",
|
||||
"svgo",
|
||||
]
|
||||
}
|
||||
}),
|
||||
new AssetJsonPlugin(),
|
||||
],
|
||||
output: {
|
||||
filename: dev ? "[name].js" : "[name].[contenthash].js",
|
||||
assetModuleFilename: assetModuleFilename,
|
||||
},
|
||||
cache: dev ? { type: "filesystem" } : false,
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (dev) {
|
||||
// eval source maps don't work with our css loaders
|
||||
config.devtool = "cheap-module-source-map";
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
const { merge } = require("webpack-merge");
|
||||
const CopyPlugin = require("copy-webpack-plugin");
|
||||
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
|
||||
const AssetJsonPlugin = require("./webpack/asset-json-plugin");
|
||||
|
||||
const common = require("./webpack.common.js");
|
||||
const entrypoints = require("./webpack/entrypoints");
|
||||
const entrypointsHtml = require("./webpack/entrypoints-html");
|
||||
|
||||
const assetModuleFilename = "[name].[contenthash][ext]";
|
||||
|
||||
module.exports = merge(common, {
|
||||
entry: entrypoints,
|
||||
plugins: [
|
||||
...entrypointsHtml,
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: "node_modules/@mozilla-protocol/core/protocol/img/icons/**",
|
||||
to: assetModuleFilename,
|
||||
},
|
||||
{ from: "kitsune/*/static/**/img/**", to: assetModuleFilename },
|
||||
],
|
||||
}),
|
||||
new ImageMinimizerPlugin({
|
||||
minimizerOptions: {
|
||||
plugins: ["optipng", "svgo"],
|
||||
},
|
||||
}),
|
||||
new AssetJsonPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: "all",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
assetModuleFilename: assetModuleFilename,
|
||||
},
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
const { mergeWithCustomize, unique } = require("webpack-merge");
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
|
||||
const dev = require("./webpack.dev.js");
|
||||
|
||||
module.exports = mergeWithCustomize({
|
||||
customizeArray: unique(
|
||||
"plugins",
|
||||
["MiniCssExtractPlugin"],
|
||||
(plugin) => plugin.constructor && plugin.constructor.name
|
||||
),
|
||||
})(dev, {
|
||||
mode: "production",
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].[contenthash].css",
|
||||
}),
|
||||
],
|
||||
cache: false,
|
||||
devtool: false,
|
||||
output: {
|
||||
filename: "[name].[contenthash].js",
|
||||
},
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
const { merge } = require("webpack-merge");
|
||||
const glob = require("glob");
|
||||
|
||||
const common = require("./webpack.common.js");
|
||||
|
||||
module.exports = merge(common, {
|
||||
target: "node",
|
||||
entry: {
|
||||
tests: [...glob.sync("./kitsune/*/static/*/js/tests/*.js")],
|
||||
},
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
protocol: "@mozilla-protocol/core/protocol",
|
||||
sumo: path.resolve(__dirname, "../kitsune/sumo/static/sumo"),
|
||||
community: path.resolve(__dirname, "../kitsune/community/static/community"),
|
||||
kpi: path.resolve(__dirname, "../kitsune/kpi/static/kpi"),
|
||||
};
|
|
@ -3,7 +3,11 @@ module.exports = {
|
|||
"plugin:import/recommended",
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": "webpack",
|
||||
"import/resolver": {
|
||||
"webpack": {
|
||||
"config": "./webpack.common.js",
|
||||
},
|
||||
},
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
module.exports = [
|
||||
// we copy these libraries from external sources, so define their exports here,
|
||||
// rather than having to modify them, making updating them more difficult:
|
||||
exports(
|
||||
"../kitsune/sumo/static/sumo/js/libs/dnt-helper.js",
|
||||
"default Mozilla.dntEnabled"
|
||||
),
|
||||
exports(
|
||||
"../kitsune/sumo/static/sumo/js/libs/uitour.js",
|
||||
"default Mozilla.UITour"
|
||||
),
|
||||
];
|
||||
|
||||
function exports(path, exports) {
|
||||
// export the named variable
|
||||
return {
|
||||
test: require.resolve(path),
|
||||
loader: "exports-loader",
|
||||
options: {
|
||||
type: "module",
|
||||
exports,
|
||||
},
|
||||
};
|
||||
}
|
|
@ -1,15 +1,21 @@
|
|||
require("@babel/register")({
|
||||
plugins: [
|
||||
[
|
||||
"module-resolver",
|
||||
{
|
||||
// make babel resolve our webpack aliases in tests
|
||||
alias: require("./aliases"),
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
require('source-map-support').install();
|
||||
|
||||
// make images imports return null, we don't need them in tests
|
||||
require.extensions[".svg"] = () => null;
|
||||
require.extensions[".png"] = () => null;
|
||||
const jsdom = require("jsdom");
|
||||
const { JSDOM } = jsdom;
|
||||
const dom = new JSDOM("<html></html>", {
|
||||
url: "https://example.com",
|
||||
referrer: "http://google.com/?q=cookies",
|
||||
});
|
||||
global.window = dom.window;
|
||||
global.document = dom.window.document;
|
||||
global.navigator = dom.window.navigator;
|
||||
global.sessionStorage = dom.window.sessionStorage;
|
||||
global.history = dom.window.history;
|
||||
global.Element = dom.window.Element;
|
||||
global.matchMedia = () => ({
|
||||
matches : false,
|
||||
addListener : () =>{},
|
||||
removeListener: () =>{},
|
||||
});
|
||||
global.jQuery = global.$ = require("jquery");
|
||||
require("../kitsune/sumo/static/sumo/js/i18n");
|
||||
|
|
Загрузка…
Ссылка в новой задаче