提交 b52bd327 编写于 作者: F Félix Queiruga

Migrates unit tests to Jest

- Jest was chosen because it's the most feature-complete one
- Fixes tests so that they would work with the new JS modules
- Removed the gulpfile unused test dependencies
- Enabled tests in maven
上级 965dbafd
{
"transform": {
"\\.hbs$": "jest-handlebars",
"\\.js$": "babel-jest"
}
}
......@@ -14,19 +14,20 @@
"prod": "webpack --config webpack.config.js --mode=production",
"build": "yarn prod",
"start": "yarn copy-fonts && yarn dev --watch",
"test": "babel ./node_modules/jasmine/bin/jasmine.js src/test/js/widgets/config/tabbar-spec.js"
"test": "jest --config=jest.config.json"
},
"devDependencies": {
"@babel/cli": "^7.7.4",
"@babel/core": "^7.7.4",
"@jenkins-cd/js-test": "^1.2.3",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^5.1.1",
"css-loader": "^3.2.0",
"file-loader": "^5.0.2",
"handlebars": "^3.0.3",
"handlebars-loader": "^1.7.1",
"jasmine": "^3.5.0",
"jenkins-js-test": "^1.0.0",
"jest": "^24.9.0",
"jest-handlebars": "^1.0.1",
"jshint": "^2.10.3",
"less": "^3.10.3",
"less-loader": "^5.0.0",
......@@ -41,7 +42,6 @@
"bootstrap": "3.3.5",
"jenkins-js-modules": "^1.5.0",
"jquery": "2.1.4",
"jquery-detached": "^2.1.4-v2",
"window-handle": "^1.0.0"
},
"browserslist": [
......
......@@ -656,6 +656,17 @@ THE SOFTWARE.
</configuration>
</execution>
<execution>
<phase>test</phase>
<id>yarn test</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>test</arguments>
<skip>${skipTests}</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
......
......@@ -10,6 +10,10 @@ var breadcrumbBarHeight = page.breadcrumbBarHeight();
// Some stuff useful for testing.
export var tabbars = [];
export var scrollspeed = 500;
// Used to set scrollspeed from the the test suite
export function setScrollspeed(newScrollspeed) {
scrollspeed = newScrollspeed;
}
var eventListeners = [];
export var on = function(listener) {
eventListeners.push(listener);
......
......@@ -378,7 +378,7 @@ function isTestEnv() {
return true;
} else if (window.navigator.userAgent === 'JenkinsTest') {
return true;
} else if (window.navigator.userAgent.toLowerCase().indexOf("node.js") !== -1) {
} else if (window.navigator.userAgent.toLowerCase().indexOf("jsdom") !== -1) {
return true;
}
......
var jsTest = require("jenkins-js-test");
var jquery = require('jquery-detached');
import jsTest from '@jenkins-cd/js-test';
var debug = false;
var getJQuery = function() {
var $ = jquery.getJQuery();
var $ = require('jquery');
$.fx.off = true;
return $;
};
var getJenkins = function() {
return require('../../main/js/util/jenkins').default;
}
var getSetupWizardGui = function() {
return require('../../main/js/pluginSetupWizardGui').default;
}
/* globals defaultUpdateSiteId: true */
defaultUpdateSiteId = 'default';
global.defaultUpdateSiteId = 'default';
// Iterates through all responses until the end and returns the last response repeatedly
var LastResponse = function(responses) {
......@@ -146,9 +153,9 @@ var ajaxMocks = function(responseMappings) {
console.log('AJAX call: ' + call.url);
}
var response = responseMappings[call.url];
var response = responseMappings[call.url] || responseMappings[`/jenkins${call.url}`];
if (!response) {
response = defaultMappings[call.url];
response = defaultMappings[call.url] || defaultMappings[`/jenkins${call.url}`];
}
if (!response) {
throw 'No data mapping provided for AJAX call: ' + call.url;
......@@ -161,30 +168,25 @@ var ajaxMocks = function(responseMappings) {
};
// call this for each test, it will provide a new wizard, jquery to the caller
var test = function(test, ajaxMappings) {
var test = function(testCallback, { ajaxMappings, $, $body }) {
jsTest.onPage(function() {
// deps
var $ = getJQuery();
// Respond to status request
$.ajax = ajaxMocks(ajaxMappings);
// load the module
var pluginSetupWizard = jsTest.requireSrcModule('pluginSetupWizardGui');
var pluginSetupWizard = getSetupWizardGui();
// exported init
pluginSetupWizard.init('body');
pluginSetupWizard.init($body);
test($, pluginSetupWizard);
testCallback($, pluginSetupWizard);
});
};
// helper to validate the appropriate plugins were installed
var validatePlugins = function(plugins, complete) {
var jenkins = jsTest.requireSrcModule('util/jenkins');
if(!jenkins.originalPost) {
jenkins.originalPost = jenkins.post;
}
var jenkins = getJenkins();
jenkins.post = function(url, data, cb) {
expect(url).toBe('/pluginManager/installPlugins');
var allMatch = true;
......@@ -206,22 +208,42 @@ var validatePlugins = function(plugins, complete) {
};
describe("pluginSetupWizard.js", function () {
let $;
let $body;
beforeEach(() => {
// Registers needed handlebars helpers that are loaded through webpack
const Handlebars = require('handlebars').default;
Handlebars.registerHelper('id', require('../../main/js/handlebars-helpers/id').default)
// Create a new <body> tag for every test
$ = getJQuery();
$body = $('<body>');
});
afterEach(() => {
$body = null;
$ = null;
// Reset changes made to modules, such as the 'util/jenkins' module.
jest.resetModules();
});
it("wizard shows", function (done) {
test(function($) {
// Make sure the dialog was shown
var $wizard = $('.plugin-setup-wizard');
var $wizard = $body.find('.plugin-setup-wizard');
expect($wizard.size()).toBe(1);
done();
});
}, { $, $body });
});
it("offline shows", function (done) {
jsTest.onPage(function() {
// deps
var jenkins = jsTest.requireSrcModule('./util/jenkins');
const jenkins = getJenkins();
var $ = getJQuery();
$.ajax = ajaxMocks();
var get = jenkins.get;
......@@ -247,16 +269,16 @@ describe("pluginSetupWizard.js", function () {
};
// load the module
var pluginSetupWizard = jsTest.requireSrcModule('pluginSetupWizardGui');
const pluginSetupWizard = getSetupWizardGui();
// exported init
pluginSetupWizard.init('body');
pluginSetupWizard.init($body);
expect($('.welcome-panel h1').text()).toBe('Offline');
expect($body.find('.welcome-panel h1').text()).toBe('Offline');
done();
done();
} finally {
jenkins.get = get;
jenkins.get = get;
}
});
});
......@@ -264,10 +286,10 @@ describe("pluginSetupWizard.js", function () {
it("install defaults", function (done) {
test(function($) {
// Make sure the dialog was shown
var wizard = $('.plugin-setup-wizard');
var wizard = $body.find('.plugin-setup-wizard');
expect(wizard.size()).toBe(1);
var goButton = $('.install-recommended');
var goButton = $body.find('.install-recommended');
expect(goButton.size()).toBe(1);
// validate a call to installPlugins with our defaults
......@@ -276,43 +298,45 @@ describe("pluginSetupWizard.js", function () {
});
goButton.click();
});
}, { $, $body });
});
var doit = function($, sel, trigger) {
var $el = $(sel);
if($el.length !== 1) {
console.log('Not found! ' + sel);
console.log(new Error().stack);
}
if(trigger === 'check') {
$el.prop('checked', true);
trigger = 'change';
}
$el.trigger(trigger);
};
it("install custom", function (done) {
function doit($body, selector, trigger) {
var $el = $body.find(selector);
if($el.length !== 1) {
console.log('Not found! ' + selector);
console.log(new Error().stack);
}
if(trigger === 'check') {
$el.prop('checked', true);
trigger = 'change';
}
$el.trigger(trigger);
};
test(function($) {
$('.install-custom').click();
$body.find('.install-custom').click();
// validate a call to installPlugins with our defaults
validatePlugins(['junit','mailer'], function() {
// install a specific, other 'set' of plugins
$('input[name=searchbox]').val('junit');
$body.find('input[name=searchbox]').val('junit');
done();
});
doit($, 'input[name=searchbox]', 'blur');
doit($body, 'input[name=searchbox]', 'blur');
doit($, '.plugin-select-none', 'click');
doit($body, '.plugin-select-none', 'click');
doit($, 'input[name="junit"]', 'check');
doit($, 'input[name="mailer"]', 'check');
doit($body, 'input[name="junit"]', 'check');
doit($body, 'input[name="mailer"]', 'check');
doit($, '.install-selected', 'click');
});
doit($body, '.install-selected', 'click');
}, { $, $body });
});
it("restart required", function (done) {
......@@ -332,11 +356,12 @@ describe("pluginSetupWizard.js", function () {
}
},
};
test(function($) {
expect($('.install-done').size()).toBe(0);
expect($('.install-done-restart').size()).toBe(1);
test(function() {
expect($body.find('.install-done').size()).toBe(0);
expect($body.find('.install-done-restart').size()).toBe(1);
done();
}, ajaxMappings);
}, { ajaxMappings, $, $body });
});
it("restart required not supported", function (done) {
......@@ -357,10 +382,10 @@ describe("pluginSetupWizard.js", function () {
},
};
test(function($) {
expect($('.install-done').size()).toBe(0);
expect($('.install-done-restart').size()).toBe(0);
expect($body.find('.install-done').size()).toBe(0);
expect($body.find('.install-done-restart').size()).toBe(0);
done();
}, ajaxMappings);
}, { ajaxMappings, $, $body });
});
it("restart not required", function (done) {
......@@ -380,11 +405,11 @@ describe("pluginSetupWizard.js", function () {
}
},
};
test(function($) {
expect($('.install-done').size()).toBe(1);
expect($('.install-done-restart').size()).toBe(0);
test(function() {
expect($body.find('.install-done').size()).toBe(1);
expect($body.find('.install-done-restart').size()).toBe(0);
done();
}, ajaxMappings);
}, { ajaxMappings, $, $body });
});
it("resume install", function (done) {
......@@ -399,11 +424,11 @@ describe("pluginSetupWizard.js", function () {
}
}
};
test(function($) {
expect($('.modal-title').text()).toBe('Resume Installation');
expect($('*[data-name="junit"]').is('.success')).toBe(true);
done();
}, ajaxMappings);
test(function() {
expect($body.find('.modal-title').text()).toBe('Resume Installation');
expect($body.find('*[data-name="junit"]').is('.success')).toBe(true);
done();
}, { ajaxMappings, $, $body });
});
it("error conditions", function (done) {
......@@ -418,18 +443,13 @@ describe("pluginSetupWizard.js", function () {
}
}
};
test(function($) {
expect($('.error-container h1').html()).toBe('Error');
done();
}, ajaxMappings);
test(function() {
expect($body.find('.error-container h1').html()).toBe('Error');
done();
}, { ajaxMappings, $, $body });
});
it("restart required", function (done) {
var jenkins = jsTest.requireSrcModule('util/jenkins');
if(jenkins.originalPost) {
jenkins.post = jenkins.originalPost;
}
var ajaxMappings = {
'/jenkins/updateCenter/installStatus': new LastResponse([{
status: 'ok',
......@@ -461,21 +481,19 @@ describe("pluginSetupWizard.js", function () {
}
])
};
test(function($) {
var goButton = $('.install-recommended');
test(function() {
var goButton = $body.find('.install-recommended');
expect(goButton.size()).toBe(1);
// validate a call to installPlugins with our defaults
setTimeout(function() {
expect($('.install-done').is(':visible')).toBe(false);
expect($('.installing-panel').is(':visible')).toBe(true);
expect($body.find('.install-done').length).toBe(0);
expect($body.find('.installing-panel').length).toBe(1)
done();
}, 1);
goButton.click();
}, ajaxMappings);
}, { ajaxMappings, $, $body });
});
});
\ No newline at end of file
});
// TODO: remove or do something about this when reenabling the unit tests
var jsTest = require("jenkins-js-test");
const jsTest = require("@jenkins-cd/js-test");
// mock the behaviors stuff.
var behaviorShim = require('../../../../main/js/util/behavior-shim');
......
var jsTest = require("jenkins-js-test");
import fs from 'fs';
import path from 'path';
import jsTest from '@jenkins-cd/js-test';
import './mocks';
require('./mocks');
const debug = false;
const htmlContent = fs.readFileSync(
path.resolve(__dirname, './freestyle-config-scrollspy.html'),
'utf8'
);
describe("scrollspy-spec tests", function () {
// Need to mock the utils/page module because we will hijack the scroll events
const mockPageUtils = jest.requireActual('../../../../main/js/util/page');
const mockWinScrollTop = jest.fn();
const mockOnWinScroll = jest.fn();
// Need to mock the .isVisible() function of the ConfigSection model because
// it needs to return true for these tests and it's current implementation
// would return false
const mockConfigSection = jest.requireActual(
'../../../../main/js/widgets/config/model/ConfigSection'
);
beforeEach(() => {
jest.mock('../../../../main/js/util/page', () => ({
...mockPageUtils,
winScrollTop: mockWinScrollTop,
onWinScroll: mockOnWinScroll,
}));
mockConfigSection.prototype.isVisible = jest.fn();
jest.mock(
'../../../../main/js/widgets/config/model/ConfigSection',
() => mockConfigSection
);
});
afterEach(() => {
// Mock cleanup so that it will not affect other tests
jest.resetAllMocks();
jest.resetModules();
});
// Declared here to take advantage of the mockPageUtils in the closure scope
function newManualScroller() {
var scrollListeners = [];
var curScrollToTop = 0;
mockWinScrollTop.mockImplementation(() => curScrollToTop);
mockOnWinScroll.mockImplementation((listener) => {
scrollListeners.push(listener);
})
return {
scrollTo: function(position) {
curScrollToTop = position;
for (var i = 0; i < scrollListeners.length; i++) {
scrollListeners[i]();
}
}
};
}
it("- test scrolling", function (done) {
// Needs to return true for the tests
mockConfigSection.prototype.isVisible.mockReturnValue(true);
jsTest.onPage(function () {
document.documentElement.innerHTML = htmlContent;
var manualScroller = newManualScroller();
var tabbars = jsTest.requireSrcModule('config-scrollspy.js');
tabbars.scrollspeed = 1; // speed up the scroll speed for testing
var tabbars = require('../../../../main/js/config-scrollspy');
tabbars.setScrollspeed(1); // speed up the scroll speed for testing
var tabbar = tabbars.tabbars[0];
......@@ -73,7 +137,10 @@ describe("scrollspy-spec tests", function () {
// which is not what happens if you try scrolling to this last section
// (see above).
tabbar.getSection('config__build').activate();
}, 'widgets/config/freestyle-config-scrollspy.html');
// Need to pass the HTML string because jsTest will not load the content
// if it only receives a filename
}, htmlContent);
});
});
......@@ -86,32 +153,15 @@ function doSectionFunctionMocking(tabbar) {
var mainOffset = 100;
var height = 40;
console.log('*** Mocking the position/offset of the form sections:');
if (debug) {
console.log('*** Mocking the position/offset of the form sections:');
}
for (var i = 0; i < tabbar.sections.length; i++) {
var section = tabbar.sections[i];
var offset = (mainOffset + (height * i));
console.log('\t' + section.id + ': ' + offset);
if (debug) {
console.log('\t' + section.id + ': ' + offset);
}
doMocks(section, offset);
}
}
function newManualScroller() {
var page = jsTest.requireSrcModule('util/page.js');
var scrollListeners = [];
var curScrollToTop = 0;
page.winScrollTop = function() {
return curScrollToTop;
};
page.onWinScroll = function(listener) {
scrollListeners.push(listener);
};
return {
scrollTo: function(position) {
curScrollToTop = position;
for (var i = 0; i < scrollListeners.length; i++) {
scrollListeners[i]();
}
}
};
}
\ No newline at end of file
var jsTest = require("jenkins-js-test");
import fs from 'fs';
import path from 'path';
import $ from 'jquery';
import jsTest from '@jenkins-cd/js-test';
import './mocks';
require('./mocks');
const htmlConfigTabbedContent = fs.readFileSync(
path.resolve(__dirname, './freestyle-config-tabbed.html'),
'utf8'
);
function getConfigTabbar() {
return require('../../../../main/js/config-tabbar');
}
function getConfigTabbarWidget() {
return require('../../../../main/js/widgets/config/tabbar');
}
describe("tabbar-spec tests", function () {
it("- test section count", function (done) {
jsTest.onPage(function() {
var tabbars = jsTest.requireSrcModule('config-tabbar.js');
var firstTableMetadata = tabbars.tabs[0];
document.documentElement.innerHTML = htmlConfigTabbedContent;
var jQD = require('jquery-detached');
var $ = jQD.getJQuery();
var tabbars = getConfigTabbar();
var firstTableMetadata = tabbars.tabs[0];
expect($('.section-header-row', firstTableMetadata.configTable).size()).toBe(4);
expect(firstTableMetadata.configTable.find('.section-header-row').length).toBe(4);
expect(firstTableMetadata.sectionCount()).toBe(4);
expect($('.tabBar .tab').size()).toBe(4);
expect(firstTableMetadata.sectionIds().toString())
.toBe('config_general,config__advanced_project_options,config__build_triggers,config__build');
expect(firstTableMetadata.sectionIds()).toEqual([
'config_general',
'config__advanced_project_options',
'config__build_triggers',
'config__build'
])
done();
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test section activation", function (done) {
jsTest.onPage(function() {
var tabbars = jsTest.requireSrcModule('config-tabbar.js');
document.documentElement.innerHTML = htmlConfigTabbedContent;
var tabbars = getConfigTabbar();
var firstTableMetadata = tabbars.tabs[0];
// The first section ("General") should be active by default
......@@ -49,12 +69,14 @@ describe("tabbar-spec tests", function () {
firstTableMetadata.activateSection('config__build');
// above 'firstTableMetadata.onShowSection' handler should get called now
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test row-group modeling", function (done) {
jsTest.onPage(function() {
var configTabBar = jsTest.requireSrcModule('widgets/config/tabbar');
document.documentElement.innerHTML = htmlConfigTabbedContent;
var configTabBar = getConfigTabbarWidget();
var firstTableMetadata = configTabBar.addTabsOnFirst();
var generalSection = firstTableMetadata.activeSection();
......@@ -71,17 +93,15 @@ describe("tabbar-spec tests", function () {
expect(generalSection.getRowGroupLabels().toString()).toBe('Discard Old Builds');
done();
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test finder - via handler triggering", function (done) {
jsTest.onPage(function() {
var configTabBarWidget = jsTest.requireSrcModule('widgets/config/tabbar');
var configTabBar = configTabBarWidget.addTabsOnFirst();
var jQD = require('jquery-detached');
var $ = jQD.getJQuery();
document.documentElement.innerHTML = htmlConfigTabbedContent;
var configTabBarWidget = getConfigTabbarWidget();
var configTabBar = configTabBarWidget.addTabsOnFirst();
var tabBar = $('.tabBar');
// All tabs should be visible...
......@@ -107,17 +127,15 @@ describe("tabbar-spec tests", function () {
done();
}, 600);
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test finder - via showSections()", function (done) {
jsTest.onPage(function() {
var configTabBarWidget = jsTest.requireSrcModule('widgets/config/tabbar');
var configTabBar = configTabBarWidget.addTabsOnFirst();
var jQD = require('jquery-detached');
var $ = jQD.getJQuery();
document.documentElement.innerHTML = htmlConfigTabbedContent;
var configTabBarWidget = getConfigTabbarWidget();
var configTabBar = configTabBarWidget.addTabsOnFirst();
var tabBar = $('.tabBar');
configTabBar.showSections('quiet period');
......@@ -128,17 +146,15 @@ describe("tabbar-spec tests", function () {
expect(textCleanup(activeSection.title)).toBe('#Advanced Project Options');
done();
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test finder - via showSections() - in inner row-group", function (done) {
jsTest.onPage(function() {
var configTabBarWidget = jsTest.requireSrcModule('widgets/config/tabbar');
var configTabBar = configTabBarWidget.addTabsOnFirst();
var jQD = require('jquery-detached');
var $ = jQD.getJQuery();
document.documentElement.innerHTML = htmlConfigTabbedContent;
var configTabBarWidget = getConfigTabbarWidget();
var configTabBar = configTabBarWidget.addTabsOnFirst();
var tabBar = $('.tabBar');
configTabBar.showSections('Strategy');
......@@ -149,17 +165,15 @@ describe("tabbar-spec tests", function () {
expect(textCleanup(activeSection.title)).toBe('General');
done();
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test adopt sections ", function (done) {
jsTest.onPage(function() {
var configTabBarWidget = jsTest.requireSrcModule('widgets/config/tabbar');
var configTabBar = configTabBarWidget.addTabsOnFirst();
var jQD = require('jquery-detached');
var $ = jQD.getJQuery();
document.documentElement.innerHTML = htmlConfigTabbedContent;
var configTabBarWidget = getConfigTabbarWidget();
var configTabBar = configTabBarWidget.addTabsOnFirst();
var tabBar = $('.tabBar');
// Move the advanced stuff into the general section
......@@ -182,12 +196,14 @@ describe("tabbar-spec tests", function () {
expect(textCleanup(activeSection.title)).toBe('General');
done();
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
it("- test getSibling ", function (done) {
jsTest.onPage(function() {
var configTabBarWidget = jsTest.requireSrcModule('widgets/config/tabbar');
document.documentElement.innerHTML = htmlConfigTabbedContent;
var configTabBarWidget = getConfigTabbarWidget();
var configTabBar = configTabBarWidget.addTabsOnFirst();
// console.log('**** ' + configTabBar.sectionIds());
......@@ -213,13 +229,10 @@ describe("tabbar-spec tests", function () {
expect(config__advanced_project_options.getSibling(+3)).toBeUndefined();
done();
}, 'widgets/config/freestyle-config-tabbed.html');
}, htmlConfigTabbedContent);
});
function keydowns(text, onInput) {
var jQD = require('jquery-detached');
var $ = jQD.getJQuery();
// hmmm, for some reason, the key events do not result in the text being
// set in the input, so setting it manually.
onInput.val(text);
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册