Setup jest unit tests and add basic test cases for AB.js and App.vue
Bug: T300561 Change-Id: Ib7c314b094bd823ae233374f63c9094724d6c06f
This commit is contained in:
parent
44e6289f8d
commit
66359e8fa5
|
@ -3,3 +3,4 @@
|
|||
/i18n/
|
||||
/node_modules/
|
||||
/vendor/
|
||||
/coverage/
|
||||
|
|
|
@ -22,6 +22,7 @@ sftp-config.json
|
|||
/docs
|
||||
/node_modules
|
||||
/vendor
|
||||
/coverage
|
||||
|
||||
# Operating systems
|
||||
## Mac OS X
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
/node_modules/
|
||||
/skinStyles/jquery.ui/
|
||||
/vendor/
|
||||
/coverage/
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
// For a detailed explanation regarding each configuration property, visit:
|
||||
// https://jestjs.io/docs/en/configuration.html
|
||||
|
||||
module.exports = {
|
||||
moduleNameMapper: {
|
||||
},
|
||||
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
|
||||
// Indicates whether the coverage information should be collected while executing the test
|
||||
collectCoverage: true,
|
||||
|
||||
// An array of glob patterns indicating a set of files fo
|
||||
// which coverage information should be collected
|
||||
collectCoverageFrom: [
|
||||
'resources/**/*.(js|vue)'
|
||||
],
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: 'coverage',
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
coveragePathIgnorePatterns: [
|
||||
'/node_modules/'
|
||||
],
|
||||
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 0,
|
||||
functions: 0,
|
||||
lines: 0,
|
||||
statements: 0
|
||||
}
|
||||
},
|
||||
|
||||
// A set of global variables that need to be available in all test environments
|
||||
globals: {
|
||||
'vue-jest': {
|
||||
babelConfig: false,
|
||||
hideStyleWarn: true,
|
||||
experimentalCSSCompile: true
|
||||
}
|
||||
},
|
||||
|
||||
// An array of file extensions your modules use
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'json',
|
||||
'vue'
|
||||
],
|
||||
|
||||
// The paths to modules that run some code to configure or
|
||||
// set up the testing environment before each test
|
||||
setupFiles: [
|
||||
'./jest.setup.js'
|
||||
],
|
||||
|
||||
transform: {
|
||||
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
|
||||
}
|
||||
};
|
|
@ -0,0 +1,4 @@
|
|||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
var mockMediaWiki = require( '@wikimedia/mw-node-qunit/src/mockMediaWiki.js' );
|
||||
global.mw = mockMediaWiki();
|
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -2,7 +2,8 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"start": "bash dev-scripts/setup-storybook.sh && start-storybook --quiet -p 6006 -s resources/skins.vector.styles",
|
||||
"test": "npm -s run lint && tsc && npm -s run doc",
|
||||
"test": "npm -s run lint && tsc && npm run test:unit && npm -s run doc",
|
||||
"test:unit": "jest --silent",
|
||||
"lint": "npm -s run lint:js && npm -s run lint:styles && npm -s run lint:i18n",
|
||||
"lint:fix:js": "npm -s run lint:js -- --fix",
|
||||
"lint:fix:styles": "npm -s run lint:styles -- --fix",
|
||||
|
@ -18,14 +19,18 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "7.7.7",
|
||||
"@storybook/html": "5.2.8",
|
||||
"@types/jest": "26.0.24",
|
||||
"@types/jquery": "3.3.33",
|
||||
"@types/mustache": "4.0.1",
|
||||
"@types/node-fetch": "2.5.7",
|
||||
"@vue/test-utils": "1.1.0",
|
||||
"@wikimedia/mw-node-qunit": "6.3.0",
|
||||
"@wikimedia/types-wikimedia": "0.2.0",
|
||||
"@wikimedia/wvui": "0.3.0",
|
||||
"@wikimedia/wvui": "0.3.5",
|
||||
"babel-loader": "8.0.6",
|
||||
"eslint-config-wikimedia": "0.20.0",
|
||||
"grunt-banana-checker": "0.9.0",
|
||||
"jest": "26.4.2",
|
||||
"jsdoc": "3.6.7",
|
||||
"jsdoc-wmf-theme": "0.0.3",
|
||||
"less": "3.8.1",
|
||||
|
@ -36,6 +41,7 @@
|
|||
"stylelint-config-wikimedia": "0.11.1",
|
||||
"svgo": "2.3.1",
|
||||
"typescript": "4.5.5",
|
||||
"vue": "2.6.11"
|
||||
"vue": "2.6.11",
|
||||
"vue-jest": "3.0.7"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,5 +116,9 @@ function initAB( bucket ) {
|
|||
module.exports = {
|
||||
isInTestGroup,
|
||||
getEnabledExperiment,
|
||||
initAB
|
||||
initAB,
|
||||
test: {
|
||||
getBucketName,
|
||||
getABTestGroupExperimentName
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"../.eslintrc.json"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
"rules": {
|
||||
"es/no-object-assign": "off"
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
"node": true,
|
||||
"jest": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
const mockConfig = require( './__mocks__/config.json' );
|
||||
const ABTestConfig = mockConfig.wgVectorWebABTestEnrollment;
|
||||
|
||||
// Mock out virtual config.json file used in AB.js, before importing AB.js
|
||||
jest.mock( '../../resources/skins.vector.es6/config.json', () => {
|
||||
return mockConfig;
|
||||
}, { virtual: true } );
|
||||
const AB = require( '../../resources/skins.vector.es6/AB.js' );
|
||||
|
||||
describe( 'AB.js', () => {
|
||||
const bucket = 'sampled';
|
||||
const userId = '1';
|
||||
const getBucketMock = jest.fn().mockReturnValue( bucket );
|
||||
const toStringMock = jest.fn().mockReturnValue( userId );
|
||||
mw.experiments.getBucket = getBucketMock;
|
||||
// @ts-ignore
|
||||
mw.user.getId = () => ( { toString: toStringMock } );
|
||||
|
||||
const expectedABTestGroupExperimentName = {
|
||||
group: bucket,
|
||||
experimentName: ABTestConfig.name
|
||||
};
|
||||
|
||||
describe( 'getBucketName', () => {
|
||||
it( 'calls mw.experiments.getBucket with config data', () => {
|
||||
expect( AB.test.getBucketName() ).toBe( bucket );
|
||||
expect( getBucketMock ).toBeCalledWith( {
|
||||
name: ABTestConfig.name,
|
||||
enabled: ABTestConfig.enabled,
|
||||
buckets: {
|
||||
unsampled: ABTestConfig.buckets.unsampled.samplingRate,
|
||||
control: ABTestConfig.buckets.control.samplingRate,
|
||||
stickyHeaderDisabled: ABTestConfig.buckets.stickyHeaderDisabled.samplingRate,
|
||||
stickyHeaderEnabled: ABTestConfig.buckets.stickyHeaderEnabled.samplingRate
|
||||
}
|
||||
}, userId );
|
||||
expect( toStringMock ).toHaveBeenCalled();
|
||||
} );
|
||||
} );
|
||||
describe( 'getABTestGroupExperimentName', () => {
|
||||
it( 'returns group and experiment name object', () => {
|
||||
expect( AB.test.getABTestGroupExperimentName() )
|
||||
.toEqual( expectedABTestGroupExperimentName );
|
||||
} );
|
||||
} );
|
||||
describe( 'getEnabledExperiment', () => {
|
||||
it( 'returns AB config data when enabled', () => {
|
||||
expect( AB.getEnabledExperiment() ).toEqual(
|
||||
Object.assign( {}, expectedABTestGroupExperimentName, ABTestConfig )
|
||||
);
|
||||
} );
|
||||
} );
|
||||
describe( 'initAB(', () => {
|
||||
const hookMock = jest.fn().mockReturnValue( { fire: () => {} } );
|
||||
const isAnonMock = jest.fn();
|
||||
mw.user.isAnon = isAnonMock;
|
||||
mw.hook = hookMock;
|
||||
it( 'sends data to WikimediaEvents when the AB test is enabled ', () => {
|
||||
isAnonMock.mockReturnValueOnce( false );
|
||||
AB.initAB( 'sampled' );
|
||||
expect( hookMock ).toHaveBeenCalled();
|
||||
} );
|
||||
it( 'doesnt send data to WikimediaEvents when the user is anon ', () => {
|
||||
isAnonMock.mockReturnValueOnce( true );
|
||||
AB.initAB( 'sampled' );
|
||||
expect( hookMock ).not.toHaveBeenCalled();
|
||||
} );
|
||||
it( 'doesnt send data to WikimediaEvents when the bucket is unsampled ', () => {
|
||||
isAnonMock.mockReturnValueOnce( false );
|
||||
AB.initAB( 'unsampled' );
|
||||
expect( hookMock ).not.toHaveBeenCalled();
|
||||
} );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,35 @@
|
|||
const Vue = require( 'vue' );
|
||||
const VueTestUtils = require( '@vue/test-utils' );
|
||||
const App = require( '../../resources/skins.vector.search/App.vue' );
|
||||
|
||||
// @ts-ignore
|
||||
Vue.directive( 'i18n-html', () => {} );
|
||||
|
||||
const defaultProps = {
|
||||
id: 'searchform',
|
||||
searchAccessKey: 'f',
|
||||
searchTitle: 'search',
|
||||
searchPlaceholder: 'Search MediaWiki',
|
||||
searchQuery: ''
|
||||
};
|
||||
|
||||
const mount = ( /** @type {Object} */ customProps ) => {
|
||||
// @ts-ignore
|
||||
return VueTestUtils.shallowMount( App, {
|
||||
propsData: Object.assign( {}, defaultProps, customProps ),
|
||||
mocks: {
|
||||
$i18n: ( /** @type {string} */ str ) => ( {
|
||||
text: () => str
|
||||
} )
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
describe( 'App', () => {
|
||||
it( 'renders a typeahead search component', () => {
|
||||
const wrapper = mount();
|
||||
expect(
|
||||
wrapper.element
|
||||
).toMatchSnapshot();
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"wgVectorWebABTestEnrollment": {
|
||||
"name": "vector.sticky_header",
|
||||
"enabled": true,
|
||||
"buckets": {
|
||||
"unsampled": {
|
||||
"samplingRate": 0.1
|
||||
},
|
||||
"control": {
|
||||
"samplingRate": 0.3
|
||||
},
|
||||
"stickyHeaderDisabled": {
|
||||
"samplingRate": 0.3
|
||||
},
|
||||
"stickyHeaderEnabled": {
|
||||
"samplingRate": 0.3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// Instead of mocking wvui, we ensure it matches the wvui-search module
|
||||
// i.e. https://github.com/wikimedia/mediawiki/blob/master/resources/src/wvui/wvui-search.js
|
||||
// @ts-ignore
|
||||
module.exports = require( '@wikimedia/wvui/dist/commonjs2/wvui-search.commonjs2.js' ).default;
|
|
@ -0,0 +1,35 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`App renders a typeahead search component 1`] = `
|
||||
<wvui-typeahead-search-stub
|
||||
accesskey="f"
|
||||
aria-label="Search MediaWiki"
|
||||
buttonlabel="searchbutton"
|
||||
client="[object Object]"
|
||||
domain="localhost"
|
||||
formaction=""
|
||||
highlightquery="true"
|
||||
id="searchform"
|
||||
initialinputvalue=""
|
||||
placeholder="Search MediaWiki"
|
||||
searchpagetitle="Special:Search"
|
||||
showdescription="true"
|
||||
showthumbnail="true"
|
||||
suggestionslabel="searchresults"
|
||||
title="search"
|
||||
urlgenerator="[object Object]"
|
||||
>
|
||||
<input
|
||||
name="title"
|
||||
type="hidden"
|
||||
value="Special:Search"
|
||||
/>
|
||||
|
||||
<input
|
||||
name="wprov"
|
||||
type="hidden"
|
||||
value="acrw1"
|
||||
/>
|
||||
<span />
|
||||
</wvui-typeahead-search-stub>
|
||||
`;
|
|
@ -1,5 +1,9 @@
|
|||
{
|
||||
"exclude": [ "docs", "vendor" ],
|
||||
"exclude": [
|
||||
"docs",
|
||||
"vendor",
|
||||
"coverage"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
|
|
Loading…
Reference in New Issue