示例#1
0
	describe( '#tryAndCustomizeTheme', () => {
		const pageSpy = sinon.spy();
		const isJetpackSiteSpy = ( state, siteId ) => {
			if ( siteId === 2211667 ) {
				return true;
			}
			return false;
		};
		const getCanonicalThemeSpy = ( state, siteId, themeId ) => {
			if ( themeId === 'karuna' ) {
				return { theme: themeId };
			}
			return null;
		};

		// we import it again with different name because we want to mock functions inside.
		let _tryAndCustomize;

		useMockery( ( mockery ) => {
			mockery.registerMock( 'page', pageSpy );
			mockery.registerMock( 'state/sites/selectors', {
				isJetpackSite: isJetpackSiteSpy
			} );
			mockery.registerMock( './selectors', {
				getThemeCustomizeUrl: () => 'customizer/url',
				getCanonicalTheme: getCanonicalThemeSpy,
			} );
			_tryAndCustomize = require( '../actions' ).tryAndCustomizeTheme;
		} );

		it( 'page should be called, when theme is available', () => {
			_tryAndCustomize( 'karuna-wpcom', 2211667 )( spy, () => {} );
			expect( pageSpy.calledWith( 'customizer/url' ) ).to.be.true;
		} );
	} );
示例#2
0
describe( 'flows', function() {
	let flows, user;

	useFakeDom();
	useFilesystemMocks( __dirname );

	useMockery( ( mockery ) => {
		mockery.registerMock( 'lib/abtest', {
			abtest: () => ''
		} );
	} );

	before( () => {
		user = require( 'lib/user' )();

		flows = require( 'signup/config/flows' );
		sinon.stub( flows, 'getFlows' ).returns( mockedFlows );
	} );

	it( 'should return the full flow when the user is not logged in', function() {
		assert.deepEqual( flows.getFlow( 'main' ).steps, [ 'user', 'site' ] );
	} );

	it( 'should remove the user step from the flow when the user is not logged in', function() {
		user.setLoggedIn( true );
		assert.deepEqual( flows.getFlow( 'main' ).steps, [ 'site' ] );
		user.setLoggedIn( false );
	} );
} );
示例#3
0
describe( '#accept()', function() {
	let accept;

	useFakeDom();
	useMockery();

	before( function() {
		mockery.registerSubstitute( 'event', 'component-event' );
		mockery.registerSubstitute( 'matches-selector', 'component-matches-selector' );
		mockery.registerSubstitute( 'query', 'component-query' );

		accept = require( '../' );
	} );

	beforeEach( function() {
		document.body.innerHTML = '';
	} );

	it( 'should render a dialog to the document body', function() {
		var message = 'Are you sure?',
			dialog;

		accept( message, function() {} );

		dialog = document.querySelector( '.accept-dialog' );
		expect( dialog ).to.be.an.instanceof( window.Element );
		expect( dialog.textContent ).to.equal( message );
	} );

	it( 'should trigger the callback with an accepted prompt', function( done ) {
		accept( 'Are you sure?', function( accepted ) {
			expect( accepted ).to.be.be.true;
			done();
		} );

		document.querySelector( '.button.is-primary' ).click();
	} );

	it( 'should trigger the callback with a denied prompt', function( done ) {
		accept( 'Are you sure?', function( accepted ) {
			expect( accepted ).to.be.be.false;
			done();
		} );

		document.querySelector( '.button:not( .is-primary )' ).click();
	} );

	it( 'should clean up after itself once the prompt is closed', function( done ) {
		accept( 'Are you sure?', function() {
			process.nextTick( function() {
				expect( document.querySelector( '.accept-dialog' ) ).to.be.null;

				done();
			} );
		} );

		document.querySelector( '.button.is-primary' ).click();
	} );
} );
示例#4
0
文件: flows.js 项目: noxee/wp-calypso
	describe( 'getABTestFilteredFlow', () => {
		let flows;

		useFakeDom();
		useFilesystemMocks( __dirname );

		const ABTestMock = {
			abtest: noop,
			getABTestVariation: () => {
				return null;
			},
		};

		const getABTestVariationSpy = sinon.stub( ABTestMock, 'getABTestVariation' );

		getABTestVariationSpy.onCall( 0 ).returns( 'notSiteTitle' );
		getABTestVariationSpy.onCall( 1 ).returns( 'notSiteTitle' );
		getABTestVariationSpy.onCall( 2 ).returns( 'showSiteTitleStep' );
		getABTestVariationSpy.onCall( 3 ).returns( 'showSiteTitleStep' );

		useMockery( ( mockery ) => {
			mockery.registerMock( 'lib/abtest', ABTestMock );
		} );

		before( () => {
			flows = require( 'signup/config/flows' );
			sinon.stub( flows, 'getFlows' ).returns( mockedFlows );
			sinon.stub( flows, 'insertStepIntoFlow', ( stepName, flow ) => {
				return flow;
			} );
			sinon.stub( flows, 'removeStepFromFlow', ( stepName, flow ) => {
				return flow;
			} );
		} );

		it( 'should return flow unmodified if not in main flow', () => {
			assert.equal( flows.getABTestFilteredFlow( 'test', 'testflow' ), 'testflow' );
			assert.equal( flows.insertStepIntoFlow.callCount, 0 );
			assert.equal( flows.removeStepFromFlow.callCount, 0 );
		} );

		it( 'should check AB variation in main flow', () => {
			assert.equal( flows.getABTestFilteredFlow( 'main', 'testflow' ), 'testflow' );
			assert.equal( getABTestVariationSpy.callCount, 1 );
			assert.equal( flows.insertStepIntoFlow.callCount, 0 );
		} );

		it( 'should return flow unmodified if variation is not valid', () => {
			const myFlow = {
				name: 'test flow name',
				steps: [ 1, 2, 3 ]
			};

			assert.equal( flows.getABTestFilteredFlow( 'main', myFlow ), myFlow );
			assert.equal( getABTestVariationSpy.callCount, 2 );
			assert.equal( flows.insertStepIntoFlow.callCount, 0 );
		} );
	} );
示例#5
0
describe( 'UserUtils', () => {
	let UserUtils, user, configMock;

	useFakeDom();

	useMockery( mockery => {
		configMock = sinon.stub();
		configMock.isEnabled = sinon.stub();
		mockery.registerMock( 'config', configMock );
	} );

	before( () => {
		user = require( 'lib/user' )();
		UserUtils = require( '../utils' );
	} );

	beforeEach( () => {
		configMock.returns( '/url-with-|subdomain|' );
	} );

	context( 'without logout url', () => {
		before( () => {
			configMock.isEnabled
				.withArgs( 'always_use_logout_url' )
				.returns( false );
		} );

		it( 'uses userData.logout_URL when available', () => {
			sinon.stub( user, 'get' ).returns( { logout_URL: '/userdata' } );
			expect( UserUtils.getLogoutUrl() ).to.equal( '/userdata' );
			user.get.restore();
		} );
	} );

	context( 'with logout url', () => {
		before( () => {
			configMock.isEnabled
				.withArgs( 'always_use_logout_url' )
				.returns( true );
		} );

		it( 'works when |subdomain| is not present', () => {
			configMock.returns( '/url-without-domain' );
			expect( UserUtils.getLogoutUrl() ).to.equal( '/url-without-domain' );
		} );

		it( 'replaces |subdomain| when present and have domain', () => {
			sinon.stub( user, 'get' ).returns( { localeSlug: 'es' } );
			expect( UserUtils.getLogoutUrl() ).to.equal( '/url-with-es.' );
			user.get.restore();
		} );

		it( 'replaces |subdomain| when present but no domain', () => {
			expect( UserUtils.getLogoutUrl() ).to.equal( '/url-with-' );
		} );
	} );
} );
示例#6
0
describe( 'mapped-domain', () => {
	let React,
		MappedDomain,
		props,
		TestUtils;

	before( () => {
		props = {
			selectedSite: {
				slug: 'neverexpires.wordpress.com',
				domain: 'neverexpires.com'
			},
			domain: {
				name: 'neverexpires.com',
				expirationMoment: null
			},
			settingPrimaryDomain: false,
			translate: identity
		};
	} );

	useFakeDom.withContainer();
	useMockery( mockery => {
		mockery.registerMock( 'lib/analytics', {} );
	} );

	before( () => {
		React = require( 'react' );
		TestUtils = require( 'react-addons-test-utils' );

		const ReactClass = require( 'react/lib/ReactClass' );
		ReactClass.injection.injectMixin( require( 'i18n-calypso' ).mixin );
		MappedDomain = require( '../mapped-domain.jsx' ).MappedDomain;
	} );

	it( 'should render when props.domain.expirationMoment is null', () => {
		const renderer = TestUtils.createRenderer();
		renderer.render( <MappedDomain { ...props } /> );
		const out = renderer.getRenderOutput();

		assert( out );
	} );

	it( 'should use selectedSite.slug for URLs', sinon.test( function() {
		const paths = require( 'my-sites/domains/paths' );
		const dnsStub = this.stub( paths, 'domainManagementDns' );
		const emailStub = this.stub( paths, 'domainManagementEmail' );

		const renderer = TestUtils.createRenderer();
		renderer.render( <MappedDomain { ...props } /> );
		renderer.getRenderOutput();

		assert( dnsStub.calledWith( 'neverexpires.wordpress.com', 'neverexpires.com' ) );
		assert( emailStub.calledWith( 'neverexpires.wordpress.com', 'neverexpires.com' ) );
	} ) );
} );
示例#7
0
describe( 'store', function() {
	let Dispatcher, PostFormatsStore, handler;

	// makes sure we always load fresh instance of Dispatcher
	useMockery();

	before( function() {
		Dispatcher = require( 'dispatcher' );
		spy( Dispatcher, 'register' );
		PostFormatsStore = require( '../store' );
		handler = Dispatcher.register.lastCall.args[ 0 ];
	} );

	beforeEach( function() {
		PostFormatsStore._formats = {};
	} );

	after( function() {
		Dispatcher.register.restore();
	} );

	function dispatchReceivePostFormats() {
		handler( {
			action: {
				type: 'RECEIVE_POST_FORMATS',
				siteId: DUMMY_SITE_ID,
				data: DUMMY_POST_FORMATS
			}
		} );
	}

	describe( '#get()', function() {
		it( 'should return undefined for a site where data does not exist', function() {
			expect( PostFormatsStore.get( DUMMY_SITE_ID ) ).to.be.undefined;
		} );

		it( 'should return an array of post format objects for a site where data has been received', function() {
			dispatchReceivePostFormats();

			expect( PostFormatsStore.get( DUMMY_SITE_ID ) ).to.eql( [
				{
					slug: 'image',
					label: 'Image'
				}
			] );
		} );
	} );

	describe( '.dispatchToken', function() {
		it( 'should emit a change event when receiving updates', function( done ) {
			PostFormatsStore.on( 'change', done );

			dispatchReceivePostFormats();
		} );
	} );
} );
示例#8
0
describe( 'selectors', () => {
	let hasUserRegisteredBefore;

	useFakeDom();

	useMockery( mockery => {
		mockery.registerSubstitute(
				'layout/guided-tours/config',
				'state/ui/guided-tours/test/fixtures/config' );

		const contexts = require( '../contexts' );
		hasUserRegisteredBefore = contexts.hasUserRegisteredBefore;
	} );

	describe( '#hasUserRegisteredBefore', () => {
		const cutoff = new Date( '2015-10-18T17:14:52+00:00' );

		const oldUser = {
			currentUser: {
				id: 73705554
			},
			users: {
				items: {
					73705554: { ID: 73705554, login: '******', date: '2014-10-18T17:14:52+00:00' }
				}
			},
		};

		const newUser = {
			currentUser: {
				id: 73705554
			},
			users: {
				items: {
					73705554: { ID: 73705554, login: '******', date: '2016-10-18T17:14:52+00:00' }
				}
			},
		};

		it( 'should return true for users registered before the cut-off date', () => {
			expect( hasUserRegisteredBefore( cutoff )( oldUser ) ).to.be.true;
		} );

		it( 'should return false for users registered after the cut-off date', () => {
			expect( hasUserRegisteredBefore( cutoff )( newUser ) ).to.be.false;
		} );
	} );
} );
示例#9
0
describe( 'abtest', () => {
	let abtest;
	let mockedUser = {};
	let ABTests;
	const setSpy = sinon.spy( () => {} );

	useFakeDom();
	useMockery( () => {
		require( 'lib/local-storage' )( global );
		mockery.registerMock( 'lib/abtest/active-tests', {
			mockedTest: {
				datestamp: '20160627',
				variations: {
					hide: 50,
					show: 50
				},
				defaultVariation: 'hide',
				allowExistingUsers: false
			},
			mockedTestAllowAnyLocale: {
				datestamp: '20160627',
				variations: {
					hide: 50,
					show: 50
				},
				defaultVariation: 'hide',
				localeTargets: 'any',
			},
			multipeLocaleNotEn: {
				datestamp: '20160627',
				variations: {
					hide: 50,
					show: 50
				},
				defaultVariation: 'hide',
				localeTargets: [ 'fr', 'de' ],
			},
			mockedTestFrLocale: {
				datestamp: '20160627',
				variations: {
					hide: 50,
					show: 50
				},
				defaultVariation: 'hide',
				localeTargets: [ 'fr' ],
			},
			mockedTestIlCountryCodeTarget: {
				datestamp: '20160627',
				variations: {
					hide: 50,
					show: 50
				},
				defaultVariation: 'hide',
				countryCodeTarget: 'IL',
			},
			mockedTestAllowExisting: {
				datestamp: '20160627',
				variations: {
					hide: 50,
					show: 50
				},
				defaultVariation: 'hide',
				allowExistingUsers: true
			},
		} );
		mockery.registerMock( 'store', {
			enabled: () => true,
			get: () => {
				return ABTests;
			},
			set: setSpy,
		} );
		mockery.registerMock( 'lib/user', () => {
			return {
				get: () => mockedUser
			};
		} );
		abtest = require( 'lib/abtest' ).abtest;
	} );

	describe( 'stored value', () => {
		beforeEach( () => {
			ABTests = { mockedTest_20160627: 'show' };
			setSpy.reset();
		} );
		it( 'should return stored value and skip store.set for existing users', () => {
			mockedUser = {
				localeSlug: 'en',
				date: DATE_BEFORE
			};
			navigator = {
				language: 'en',
				languages: [ 'en' ]
			};
			expect( abtest( 'mockedTest' ) ).to.equal( 'show' );
			expect( setSpy ).not.to.have.been.called;
		} );
		it( 'should return stored value and skip store.set for any user, including new, non-English users', () => {
			mockedUser = {
				localeSlug: 'de',
				date: DATE_AFTER
			};
			expect( abtest( 'mockedTest' ) ).to.equal( 'show' );
			expect( setSpy ).not.to.have.been.called;
		} );
		it( 'should return stored value and skip store.set for a logged-out user', () => {
			mockedUser = null;
			expect( abtest( 'mockedTest' ) ).to.equal( 'show' );
			expect( setSpy ).not.to.have.been.called;
		} );
	} );

	describe( 'no stored value', () => {
		beforeEach( () => {
			ABTests = {};
			setSpy.reset();
		} );
		describe( 'existing users', () => {
			beforeEach( () => {
				mockedUser = {
					localeSlug: 'en',
					date: DATE_BEFORE
				};
			} );
			it( 'should return default and skip store.set when allowExistingUsers is false', () => {
				expect( abtest( 'mockedTest' ) ).to.equal( 'hide' );
				expect( setSpy ).not.to.have.been.called;
			} );
			it( 'should call store.set when allowExistingUsers is true', () => {
				abtest( 'mockedTestAllowExisting' );
				expect( setSpy ).to.have.been.calledOnce;
			} );
		} );

		describe( 'new users', () => {
			beforeEach( () => {
				mockedUser = {
					localeSlug: 'en',
					date: DATE_AFTER
				};
			} );
			describe( 'English only users allowed (default)', () => {
				it( 'should call store.set for new users with English settings', () => {
					abtest( 'mockedTest' );
					expect( setSpy ).to.have.been.calledOnce;
				} );
				it( 'should call store.set for new users with English-Canada settings', () => {
					mockedUser.localeSlug = 'en-ca';
					abtest( 'mockedTest' );
					expect( setSpy ).to.have.been.calledOnce;
				} );
				it( 'should return default and skip store.set for new users with non-English settings', () => {
					mockedUser.localeSlug = 'de';
					expect( abtest( 'mockedTest' ) ).to.equal( 'hide' );
					expect( setSpy ).not.to.have.been.called;
				} );
			} );
			describe( 'all locales allowed', () => {
				it( 'should call store.set for new users with English settings', () => {
					abtest( 'mockedTestAllowAnyLocale' );
					expect( setSpy ).to.have.been.calledOnce;
				} );
				it( 'should call store.set for new users with non-English settings', () => {
					mockedUser.localeSlug = 'de';
					abtest( 'mockedTestAllowAnyLocale' );
					expect( setSpy ).to.have.been.calledOnce;
				} );
			} );
			describe( 'specific locales only', () => {
				it( 'should return default and skip store.set for new users with English settings', () => {
					expect( abtest( 'multipeLocaleNotEn' ) ).to.equal( 'hide' );
					expect( setSpy ).not.to.have.been.called;
				} );
				it( 'should call store.set for new users with non-English settings', () => {
					mockedUser.localeSlug = 'de';
					abtest( 'multipeLocaleNotEn' );
					expect( setSpy ).to.have.been.calledOnce;
				} );
			} );
			describe( 'fr locale only', () => {
				it( 'should return default and skip store.set for new users with non-french settings', () => {
					mockedUser.localeSlug = 'de';
					expect( abtest( 'mockedTestFrLocale' ) ).to.equal( 'hide' );
					expect( setSpy ).not.to.have.been.called;
				} );
				it( 'should call store.set for new users with fr settings', () => {
					mockedUser.localeSlug = 'fr';
					abtest( 'mockedTestFrLocale' );
					expect( setSpy ).to.have.been.calledOnce;
				} );
			} );
			describe( 'IL countryCodeTarget only', () => {
				it( 'should return default and skip store.set for new users with no GeoLocation value', () => {
					abtest( 'mockedTestIlCountryCodeTarget', null );
					expect( setSpy ).not.to.have.been.called;
				} );
				it( 'should throw error if countryCodeTarget is set but geoLocation is not passed', () => {
					expect( () => abtest( 'mockedTestIlCountryCodeTarget' ) ).to.throw(
						'Test config has geoTarget, but no geoLocation passed to abtest function'
						);
				} );
				it( 'should return default and skip store.set for new users not from Israel', () => {
					const geoLocation = 'US';
					expect( abtest( 'mockedTestIlCountryCodeTarget', geoLocation ) ).to.equal( 'hide' );
					expect( setSpy ).not.to.have.been.called;
				} );
				it( 'should call store.set for new users with from Israel', () => {
					const geoLocation = 'IL';
					abtest( 'mockedTestIlCountryCodeTarget', geoLocation );
					expect( setSpy ).to.have.been.calledOnce;
				} );
			} );
		} );
		describe( 'new-user-no-locale', () => {
			beforeEach( () => {
				mockedUser = {
					localeSlug: false,
					date: DATE_AFTER
				};
			} );
			it( 'should call store.set for new users with no locale for en only test', () => {
				abtest( 'mockedTest' );
				expect( setSpy ).to.have.been.calledOnce;
			} );
			it( 'show return default and skip store.set for new users with no locale for fr test', () => {
				navigator.language = 'de';
				expect( abtest( 'mockedTestFrLocale' ) ).to.equal( 'hide' );
				expect( setSpy ).not.to.have.been.called;
			} );
		} );
		describe( 'logged-out users', () => {
			beforeEach( () => {
				mockedUser = false;
				setSpy.reset();
				navigator = {
					language: 'en',
					languages: [ 'en' ]
				};
			} );
			it( 'should call store.set for logged-out users with English locale', () => {
				abtest( 'mockedTest' );
				expect( setSpy ).to.have.been.calledOnce;
			} );
			it( 'show return default and skip store.set for non-English navigator.language', () => {
				navigator.language = 'de';
				expect( abtest( 'mockedTest' ) ).to.equal( 'hide' );
				expect( setSpy ).not.to.have.been.called;
			} );
			it( 'should return default and skip store.set for non-English navigator.languages primary preference', () => {
				navigator.languages = [ 'de' ];
				expect( abtest( 'mockedTest' ) ).to.equal( 'hide' );
				expect( setSpy ).not.to.have.been.called;
			} );
			it( 'should return default and skip store.set for non-English IE10 userLanguage setting', () => {
				navigator = {
					userLanguage: 'de'
				};
				expect( abtest( 'mockedTest' ) ).to.equal( 'hide' );
				expect( setSpy ).not.to.have.been.called;
			} );
		} );
	} );
} );
示例#10
0
	describe( 'analytics dispatching', () => {
		const mockAnalytics = spy();
		const mockAdTracking = spy();
		let dispatch;

		useMockery( mockery => {
			mockery.registerMock( 'lib/analytics', analyticsMock( mockAnalytics ) );
			mockery.registerMock( 'lib/analytics/ad-tracking', adTrackingMock( mockAdTracking ) );

			dispatch = require( '../middleware.js' ).dispatcher;
		} );

		beforeEach( () => {
			mockAnalytics.reset();
			mockAdTracking.reset();
		} );

		it( 'should call mc.bumpStat', () => {
			dispatch( bumpStat( 'test', 'value' ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'mc.bumpStat' );
		} );

		it( 'should call tracks.recordEvent', () => {
			dispatch( recordTracksEvent( 'test', { name: 'value' } ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'tracks.recordEvent' );
		} );

		it( 'should call pageView.record', () => {
			dispatch( recordPageView( 'path', 'title' ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'pageView.record' );
		} );

		it( 'should call ga.recordEvent', () => {
			dispatch( recordGoogleEvent( 'category', 'action' ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'ga.recordEvent' );
		} );

		it( 'should call ga.recordPageView', () => {
			dispatch( recordGooglePageView( 'path', 'title' ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'ga.recordPageView' );
		} );

		it( 'should call tracks.recordEvent', () => {
			dispatch( recordTracksEvent( 'event', { name: 'value' } ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'tracks.recordEvent' );
		} );

		it( 'should call trackCustomFacebookConversionEvent', () => {
			dispatch( recordCustomFacebookConversionEvent( 'event', { name: 'value' } ) );

			expect( mockAdTracking ).to.have.been.calledWith( 'trackCustomFacebookConversionEvent' );
		} );

		it( 'should call trackCustomAdWordsRemarketingEvent', () => {
			dispatch( recordCustomAdWordsRemarketingEvent( { name: 'value' } ) );

			expect( mockAdTracking ).to.have.been.calledWith( 'trackCustomAdWordsRemarketingEvent' );
		} );

		it( 'should call analytics events with wrapped actions', () => {
			dispatch( withAnalytics( bumpStat( 'name', 'value' ), { type: 'TEST_ACTION' } ) );

			expect( mockAnalytics ).to.have.been.calledWith( 'mc.bumpStat' );
		} );
	} );
示例#11
0
describe( 'isEligibleForFreeToPaidUpsell', () => {
	const state = 'state';
	const moment = 'moment';
	const siteId = 'siteId';

	let canCurrentUser;
	let isMappedDomainSite;
	let isSiteOnFreePlan;
	let isUserRegistrationDaysWithinRange;
	let isVipSite;
	let isEligibleForFreeToPaidUpsell;

	useMockery( mockery => {
		canCurrentUser = stub();
		isMappedDomainSite = stub();
		isSiteOnFreePlan = stub();
		isUserRegistrationDaysWithinRange = stub();
		isVipSite = stub();

		mockery.registerMock( 'state/selectors/can-current-user', canCurrentUser );
		mockery.registerMock( 'state/selectors/is-mapped-domain-site', isMappedDomainSite );
		mockery.registerMock( 'state/selectors/is-site-on-free-plan', isSiteOnFreePlan );
		mockery.registerMock( 'state/selectors/is-user-registration-days-within-range', isUserRegistrationDaysWithinRange );
		mockery.registerMock( 'state/selectors/is-vip-site', isVipSite );
	} );

	before( () => {
		isEligibleForFreeToPaidUpsell = require( '../is-eligible-for-free-to-paid-upsell' );
	} );

	const meetAllConditions = () => {
		canCurrentUser.withArgs( state, siteId, 'manage_options' ).returns( true );
		isMappedDomainSite.withArgs( state, siteId ).returns( false );
		isSiteOnFreePlan.withArgs( state, siteId ).returns( true );
		isUserRegistrationDaysWithinRange.withArgs( state, moment, 0, 180 ).returns( true );
		isVipSite.withArgs( state, siteId ).returns( false );
	};

	it( 'should return false when user can not manage options', () => {
		meetAllConditions();
		canCurrentUser.withArgs( state, siteId, 'manage_options' ).returns( false );
		expect( isEligibleForFreeToPaidUpsell( state, siteId, moment ) ).to.be.false;
	} );

	it( 'should return false when site has mapped domain', () => {
		meetAllConditions();
		isMappedDomainSite.withArgs( state, siteId ).returns( true );
		expect( isEligibleForFreeToPaidUpsell( state, siteId, moment ) ).to.be.false;
	} );

	it( 'should return false when site is not on a free plan', () => {
		meetAllConditions();
		isSiteOnFreePlan.withArgs( state, siteId ).returns( false );
		expect( isEligibleForFreeToPaidUpsell( state, siteId, moment ) ).to.be.false;
	} );

	it( 'should return false when user registration days is not within range', () => {
		meetAllConditions();
		isUserRegistrationDaysWithinRange.withArgs( state, moment, 0, 180 ).returns( false );
		expect( isEligibleForFreeToPaidUpsell( state, siteId, moment ) ).to.be.false;
	} );

	it( 'should return false when site is a vip site', () => {
		meetAllConditions();
		isVipSite.withArgs( state, siteId ).returns( true );
		expect( isEligibleForFreeToPaidUpsell( state, siteId, moment ) ).to.be.false;
	} );

	it( 'should return true when all conditions are met', () => {
		meetAllConditions();
		expect( isEligibleForFreeToPaidUpsell( state, siteId, moment ) ).to.be.true;
	} );
} );
示例#12
0
describe( 'PreferencesActions', function() {
	let sandbox, PreferencesActions, getSettings, postSettings;
	const store = { get: noop, set: noop };
	const Dispatcher = { handleViewAction: noop, handleServerAction: noop };

	useSandbox( ( _sandbox ) => sandbox = _sandbox );
	useMockery();
	useNock();

	before( function() {
		mockery.registerMock( 'lib/user/utils', { isLoggedIn: () => true } );
		mockery.registerMock( 'store', store );
		mockery.registerMock( 'dispatcher', Dispatcher );
		mockery.registerMock( 'lib/wp', {
			undocumented: function() {
				return {
					me: function() {
						return {
							settings: function() {
								return {
									get: getSettings,
									update: postSettings
								};
							}
						};
					}
				};
			}
		} );

		PreferencesActions = rewire( '../actions' );
	} );

	beforeEach( function() {
		sandbox.restore();
		sandbox.stub( store, 'get' );
		sandbox.stub( store, 'set' );
		sandbox.stub( Dispatcher, 'handleViewAction' );
		sandbox.stub( Dispatcher, 'handleServerAction' );

		getSettings = sandbox.stub().callsArgWithAsync( 0, null, {
			[ USER_SETTING_KEY ]: DUMMY_PERSISTED_PREFERENCES
		} );
		postSettings = sandbox.stub().callsArgAsync( 1 );
	} );

	describe( '#fetch()', function() {
		it( 'should retrieve from localStorage and trigger a request to the REST API', function( done ) {
			store.get.restore();
			sandbox.stub( store, 'get' ).returns( DUMMY_PERSISTED_PREFERENCES );

			PreferencesActions.fetch();

			expect( store.get ).to.have.been.calledWith( LOCALSTORAGE_KEY );
			expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
				type: 'RECEIVE_ME_SETTINGS',
				data: {
					[ USER_SETTING_KEY ]: DUMMY_PERSISTED_PREFERENCES
				}
			} );

			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledTwice;
				expect( store.set ).to.have.been.calledWith( LOCALSTORAGE_KEY, DUMMY_PERSISTED_PREFERENCES );
				done();
			} );
		} );

		it( 'should not persist to localStorage from remote request if error occurs', function( done ) {
			const mergePreferencesToLocalStorage = sinon.stub();

			getSettings = sandbox.stub().callsArgWithAsync( 0, true );

			PreferencesActions.__with__( {
				mergePreferencesToLocalStorage: mergePreferencesToLocalStorage
			} )( function() {
				PreferencesActions.fetch();
				process.nextTick( function() {
					expect( mergePreferencesToLocalStorage ).to.not.have.been.called;
					done();
				} );
			} );
		} );

		it( 'should not dispatch an empty local store', function( done ) {
			store.get.restore();
			sandbox.stub( store, 'get' ).returns( undefined );

			PreferencesActions.fetch();

			expect( store.get ).to.have.been.calledWith( LOCALSTORAGE_KEY );
			expect( Dispatcher.handleServerAction ).to.not.have.been.called;

			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledOnce;
				expect( store.set ).to.have.been.calledWith(
					LOCALSTORAGE_KEY,
					DUMMY_PERSISTED_PREFERENCES
				);
				done();
			} );
		} );
	} );

	describe( '#set()', function() {
		it( 'should save to localStorage and trigger a request to the REST API', function( done ) {
			PreferencesActions.set( 'one', 1 );

			expect( store.set ).to.have.been.calledWith( LOCALSTORAGE_KEY, { one: 1 } );
			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'UPDATE_ME_SETTINGS'
			} );
			expect( postSettings ).to.have.been.calledWithMatch( JSON.stringify( {
				[ USER_SETTING_KEY ]: { one: 1 }
			} ) );

			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_ME_SETTINGS'
				} );
				done();
			} );
		} );

		it( 'should add to, not replace, existing values', function() {
			store.get.restore();
			sandbox.stub( store, 'get' ).returns( { one: 1 } );
			PreferencesActions.set( 'two', 2 );

			expect( store.set ).to.have.been.calledWith( LOCALSTORAGE_KEY, { one: 1, two: 2 } );
			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'UPDATE_ME_SETTINGS',
				data: {
					[ USER_SETTING_KEY ]: { two: 2 }
				}
			} );
		} );

		it( 'should assume a null value is to be removed', function() {
			PreferencesActions.set( 'one', 1 );
			PreferencesActions.set( 'one', null );

			expect( store.set ).to.have.been.calledWith( LOCALSTORAGE_KEY, { one: 1 } );
			expect( store.set ).to.have.been.calledWith( LOCALSTORAGE_KEY, {} );
			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'UPDATE_ME_SETTINGS',
				data: {
					[ USER_SETTING_KEY ]: { one: null }
				}
			} );
		} );

		it( 'should only dispatch a receive after all pending updates have finished', function( done ) {
			PreferencesActions.set( 'one', 1 );
			PreferencesActions.set( 'one', null );

			process.nextTick( function() {
				expect( postSettings ).to.have.been.calledTwice;
				expect( Dispatcher.handleServerAction ).to.have.been.calledOnce;
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( { type: 'RECEIVE_ME_SETTINGS' } );
				done();
			} );
		} );
	} );

	describe( '#remove()', function() {
		it( 'should remove from localStorage and trigger a request to the REST API', function( done ) {
			PreferencesActions.set( 'one', 1 );
			PreferencesActions.remove( 'one' );

			expect( store.set ).to.have.been.calledWith( LOCALSTORAGE_KEY, {} );
			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'UPDATE_ME_SETTINGS',
				data: {
					[ USER_SETTING_KEY ]: { one: 1 }
				}
			} );
			expect( postSettings ).to.have.been.calledWithMatch( JSON.stringify( {
				[ USER_SETTING_KEY ]: { one: 1 }
			} ) );

			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_ME_SETTINGS'
				} );

				done();
			} );
		} );
	} );
} );
示例#13
0
describe( 'MediaLibrarySelectedStore', function() {
	let Dispatcher, sandbox, MediaLibrarySelectedStore, handler, MediaStore;

	useFakeDom();
	useMockery( mockery => {
		mockery.registerMock( 'lib/wp', {
			me: () => ( {
				get: noop
			} ),
			site: noop
		} );
	} );

	before( function() {
		sandbox = sinon.sandbox.create();
		Dispatcher = require( 'dispatcher' );
		sandbox.spy( Dispatcher, 'register' );
		sandbox.stub( Dispatcher, 'waitFor' ).returns( true );

		MediaStore = require( '../store' );
		sandbox.stub( MediaStore, 'get', function( siteId, itemId ) {
			if ( siteId === DUMMY_SITE_ID ) {
				return DUMMY_OBJECTS[ itemId ];
			}
		} );

		MediaLibrarySelectedStore = require( '../library-selected-store' );
		handler = Dispatcher.register.lastCall.args[ 0 ];
	} );

	beforeEach( function() {
		MediaLibrarySelectedStore._media = {};
	} );

	after( function() {
		sandbox.restore();
	} );

	function dispatchSetLibrarySelectedItems( action ) {
		handler( {
			action: assign( {
				type: 'SET_MEDIA_LIBRARY_SELECTED_ITEMS',
				siteId: DUMMY_SITE_ID,
				data: [ DUMMY_TRANSIENT_MEDIA_OBJECT ]
			}, action )
		} );
	}

	function dispatchReceiveMediaItem() {
		handler( {
			action: {
				type: 'RECEIVE_MEDIA_ITEM',
				siteId: DUMMY_SITE_ID,
				data: DUMMY_MEDIA_OBJECT,
				id: DUMMY_TRANSIENT_MEDIA_OBJECT.ID
			}
		} );
	}

	function dispatchRemoveMediaItem( error ) {
		handler( {
			action: {
				error: error,
				type: 'REMOVE_MEDIA_ITEM',
				siteId: DUMMY_SITE_ID,
				data: DUMMY_TRANSIENT_MEDIA_OBJECT
			}
		} );
	}

	describe( '#get()', function() {
		it( 'should return a single value', function() {
			dispatchSetLibrarySelectedItems();

			expect( MediaLibrarySelectedStore.get( DUMMY_SITE_ID, DUMMY_TRANSIENT_MEDIA_OBJECT.ID ) ).to.eql( DUMMY_TRANSIENT_MEDIA_OBJECT );
		} );

		it( 'should return undefined for an item that does not exist', function() {
			expect( MediaLibrarySelectedStore.get( DUMMY_SITE_ID, DUMMY_TRANSIENT_MEDIA_OBJECT.ID + 1 ) ).to.be.undefined;
		} );
	} );

	describe( '#getAll()', function() {
		it( 'should return all selected media', function() {
			dispatchSetLibrarySelectedItems();

			expect( MediaLibrarySelectedStore.getAll( DUMMY_SITE_ID ) ).to.eql( [ DUMMY_TRANSIENT_MEDIA_OBJECT ] );
		} );

		it( 'should return an empty array for a site with no selected items', function() {
			expect( MediaLibrarySelectedStore.getAll( DUMMY_SITE_ID ) ).to.eql( [] );
		} );
	} );

	describe( '.dispatchToken', function() {
		it( 'should expose its dispatcher ID', function() {
			expect( MediaLibrarySelectedStore.dispatchToken ).to.not.be.undefined;
		} );

		it( 'should emit a change event when library items have been set', function( done ) {
			MediaLibrarySelectedStore.once( 'change', done );

			dispatchSetLibrarySelectedItems();
		} );

		it( 'should emit a change event when receiving updates', function( done ) {
			MediaLibrarySelectedStore.once( 'change', done );

			dispatchReceiveMediaItem();
		} );

		it( 'should replace an item when its ID has changed', function() {
			dispatchSetLibrarySelectedItems();
			dispatchReceiveMediaItem();

			expect( MediaLibrarySelectedStore.getAll( DUMMY_SITE_ID ) ).to.eql( [ DUMMY_MEDIA_OBJECT ] );
		} );

		it( 'should remove an item when REMOVE_MEDIA_ITEM is dispatched', function() {
			dispatchSetLibrarySelectedItems();
			dispatchRemoveMediaItem();

			expect( MediaLibrarySelectedStore._media[ DUMMY_SITE_ID ] ).to.be.empty;
		} );

		it( 'should clear selected items when CHANGE_MEDIA_SOURCE is dispatched', function() {
			dispatchSetLibrarySelectedItems();

			handler( {
				action: {
					type: 'CHANGE_MEDIA_SOURCE',
					siteId: DUMMY_SITE_ID,
				}
			} );

			expect( MediaLibrarySelectedStore._media[ DUMMY_SITE_ID ] ).to.be.empty;
		} );
	} );
} );
示例#14
0
export default function( dirpath ) {
	useMockery( findQuickMocks.bind( null, dirpath ), null );
}
示例#15
0
describe( 'cache-index', () => {
	useMockery( ( mockery ) => {
		mockery.registerMock( 'localforage', localforageMock );
		( { cacheIndex } = require( '../cache-index' ) );
	} );

	beforeEach( clearLocal ); // also do inside nested blocks with >1 test

	describe( '#getAll', () => {
		beforeEach( clearLocal );

		it( 'should return undefined for empty localforage', ( done ) => {
			return cacheIndex.getAll()
				.then( res => {
					try {
						expect( res ).to.equal( undefined );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
		it( 'should return index from localforage and nothing else', ( done ) => {
			const { recordsList } = testData;
			setLocalData( {
				someStoredRecord: 1,
				someOtherRecord: 2,
				[ RECORDS_LIST_KEY ]: recordsList
			} );
			return cacheIndex.getAll()
				.then( res => {
					try {
						expect( res ).to.equal( recordsList );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );

	describe( '#addItem', () => {
		beforeEach( clearLocal ); // also do inside nested blocks with >1 test

		it( 'should add item to empty index', ( done ) => {
			const key = 'unique-key';
			return cacheIndex.addItem( key )
				.then( () => {
					try {
						const currentIndex = localforageMock.getLocalData()[ RECORDS_LIST_KEY ];
						expect( currentIndex ).to.be.an( 'array' );
						expect( currentIndex[0] ).to.have.property( 'key', key );
						expect( currentIndex[0] ).to.have.property( 'timestamp' );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
		it( 'should store a pageSeriesKey when passed as third parameter', ( done ) => {
			const { postListKey, postListParams, postListPageSeriesKey } = testData;
			const normalizedParams = normalizeRequestParams( postListParams );
			return cacheIndex.addItem( postListKey, normalizedParams, postListPageSeriesKey )
				.then( () => {
					try {
						const currentIndex = localforageMock.getLocalData()[ RECORDS_LIST_KEY ];
						expect( currentIndex ).to.be.an( 'array' );
						expect( currentIndex[0] ).to.have.property( 'key', postListKey );
						expect( currentIndex[0] ).to.have.property( 'pageSeriesKey', postListPageSeriesKey );
						expect( currentIndex[0] ).to.have.property( 'timestamp' );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );

	describe( '#removeItem', () => {
		it( 'should remove item from a populated index', ( done ) => {
			const { postListKey, localDataFull } = testData;
			setLocalData( localDataFull );
			return cacheIndex.removeItem( postListKey )
				.then( () => {
					try {
						const currentIndex = localData()[ RECORDS_LIST_KEY ];
						expect( currentIndex.length ).to.eql( 2 );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );

	describe( '#pruneStaleRecords', () => {
		it( 'should prune old records', ( done ) => {
			const {
				postListKey,
				postListWithSearchKey,
				postListLocalRecord,
				postListWithSearchLocalRecord,
			} = testData;
			const now = Date.now();
			const yesterday = now - ms( '1 day' );
			setLocalData( {
				[ postListKey ]: postListLocalRecord,
				[ postListWithSearchKey ]: postListWithSearchLocalRecord,
				[ RECORDS_LIST_KEY ]: [
					{ key: postListKey, timestamp: now },
					{ key: postListWithSearchKey, timestamp: yesterday },
				]
			} );
			return cacheIndex.pruneStaleRecords( '1 hour' )
				.then( () => {
					try {
						const freshData = localData();
						const currentIndex = freshData[ RECORDS_LIST_KEY ];
						expect( currentIndex ).to.eql( [ { key: postListKey, timestamp: now } ] );
						expect( freshData ).to.have.property( postListKey, postListLocalRecord );
						expect( freshData ).to.have.property( RECORDS_LIST_KEY );
						expect( freshData ).to.not.have.property( postListWithSearchKey );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );

	describe( '#clearAll', () => {
		it( 'should clear all sync records and nothing else', ( done ) => {
			const { localDataFull } = testData;
			setLocalData( Object.assign( { someRecord: 1 }, localDataFull ) );
			return cacheIndex.clearAll()
				.then( () => {
					try {
						const freshData = localData();
						expect( freshData ).to.eql( { someRecord: 1 } );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );

	describe( '#clearPageSeries', () => {
		it( 'should clear records with matching pageSeriesKey and leave other records intact', ( done ) => {
			const {
				postListKey,
				postListNextPageKey,
				postListWithSearchKey,
				postListPageSeriesKey,
				postListDifferentPageSeriesKey,
				postListLocalRecord,
				postListNextPageParams,
				postListNextPageLocalRecord,
			} = testData;
			const now = Date.now();
			setLocalData( {
				someOtherRecord: 1,
				[ postListKey ]: postListLocalRecord,
				[ postListNextPageKey ]: postListNextPageLocalRecord,
				[ postListWithSearchKey ]: Object.assign( {}, postListLocalRecord ),
				[ RECORDS_LIST_KEY ]: [
					{ key: postListKey, pageSeriesKey: postListPageSeriesKey, timestamp: now },
					{ key: postListNextPageKey, pageSeriesKey: postListPageSeriesKey, timestamp: now },
					{ key: postListWithSearchKey, pageSerieKey: postListDifferentPageSeriesKey, timestamp: now },
				]
			} );
			return cacheIndex.clearPageSeries( postListNextPageParams )
				.then( () => {
					try {
						const freshData = localData();
						expect( freshData ).to.eql( { someOtherRecord: 1, [ postListWithSearchKey ]: postListLocalRecord, [ RECORDS_LIST_KEY ]: [ { key: postListWithSearchKey, pageSerieKey: postListDifferentPageSeriesKey, timestamp: now } ] } );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );

	describe( '#clearRecordsByParamFilter', () => {
		it( 'should clear records with reqParams that matches filter and leave other records intact', ( done ) => {
			const {
				postListKey,
				postListParams,
				postListLocalRecord,
				postListDifferentSiteKey,
				postListDifferentSiteParams,
				postListDifferentSiteLocalRecord
			} = testData;
			const now = Date.now();
			setLocalData( {
				[ postListKey ]: postListLocalRecord,
				[ postListDifferentSiteKey ]: postListDifferentSiteLocalRecord,
				[ RECORDS_LIST_KEY ]: [
					{ key: postListKey, reqParams: postListParams, pageSeriesKey: 'doesnotmatter', timestamp: now },
					{ key: postListDifferentSiteKey, reqParams: postListDifferentSiteParams, pageSeriesKey: 'stilldoesnotmatter', timestamp: now }
				]
			} );
			const matchSiteFilter = ( reqParams ) => {
				return reqParams.path === '/sites/bobinprogress2.wordpress.com/posts';
			};
			return cacheIndex.clearRecordsByParamFilter( matchSiteFilter )
				.then( () => {
					try {
						const freshData = localData();
						expect( freshData ).to.have.property( postListKey );
						expect( freshData ).to.not.have.property( postListDifferentSiteKey );
						expect( freshData[ RECORDS_LIST_KEY ].length ).to.eql( 1 );
						done();
					} catch ( err ) {
						done( err );
					}
				}, ( err ) => done( err ) );
		} );
	} );
} );
示例#16
0
describe( 'WPcom Data Actions', () => {
	let actions;

	useMockery( mockery => {
		mockery.registerMock( 'lib/wp', mockedWpcom );
		mockery.registerMock( 'lib/analytics', { mc: { bumpStat: noop }, tracks: { recordEvent: noop } } );
	} );

	beforeEach( () => {
		actions = require( 'lib/plugins/actions' );
		actions.resetQueue();
		mockedWpcom.undocumented().reset();
	} );

	useFakeDom();

	it( 'Actions should be an object', () => {
		assert.isObject( actions );
	} );

	it( 'Actions should have method installPlugin', () => {
		assert.isFunction( actions.installPlugin );
	} );

	it( 'when installing a plugin, it should send a install request to .com', done => {
		actions.installPlugin( siteData, 'test', noop )
			.then( () => {
				assert.equal( mockedWpcom.getActivity().pluginsInstallCalls, 1 );
				done();
			} )
			.catch( done );
	} );

	it( 'when installing a plugin, it should send an activate request to .com', done => {
		actions.installPlugin( siteData, 'test', noop )
			.then( () => {
				assert.equal( mockedWpcom.getActivity().pluginsActivateCalls, 1 );
				done();
			} )
			.catch( done );
	} );

	it( 'when installing a plugin, it should not send a request to .com when the site doesn\'t allow us to update its files', () => {
		actions.installPlugin( { canUpdateFiles: false }, 'test', noop );
		assert.equal( mockedWpcom.getActivity().pluginsInstallCalls, 0 );
	} );

	it( 'when installing a plugin, it should return a rejected promise if the site files can\'t be updated', done => {
		actions.installPlugin( { canUpdateFiles: false, capabilities: { manage_options: true }, }, 'test', noop )
			.then( () => done( 'Promise should be rejected' ) )
			.catch( () => done() );
	} );

	it( 'when installing a plugin, it should return a rejected promise if user can\'t manage the site', done => {
		actions.installPlugin( { canUpdateFiles: false, capabilities: { manage_options: true }, }, 'test', noop )
			.then( () => done( 'Promise should be rejected' ) )
			.catch( () => done() );
	} );

	it( 'Actions should have method removePlugin', () => {
		assert.isFunction( actions.removePlugin );
	} );

	it( 'when removing a plugin, it should send a remove request to .com', done => {
		actions.removePlugin( {
			canUpdateFiles: true,
			user_can_manage: true,
			capabilities: { manage_options: true },
		}, {}, noop )
			.then( () => {
				assert.equal( mockedWpcom.getActivity().pluginsRemoveCalls, 1 );
				done();
			} )
			.catch( done );
	} );

	it( 'when removing a plugin, it should send an deactivate request to .com', done => {
		actions.removePlugin( {
			canUpdateFiles: true,
			user_can_manage: true,
			capabilities: { manage_options: true },
			jetpack: true
		}, { active: true }, noop )
		.then( () => {
			assert.equal( mockedWpcom.getActivity().pluginsDeactivateCalls, 1 );
			done();
		} )
		.catch( done );
	} );

	it( 'when removing a plugin, it should not send a request to .com when the site doesn\'t allow us to update its files', () => {
		actions.removePlugin( { canUpdateFiles: false }, {}, noop );
		assert.equal( mockedWpcom.getActivity().pluginsRemoveCalls, 0 );
	} );
} );
示例#17
0
describe( 'SitesList', () => {
	let SitesList, Site, data;
	let sitesList, originalData, initializedSites;

	useMockery();
	useFakeDom();

	before( () => {
		Site = require( 'lib/site' );
		SitesList = require( '../list' );
		data = require( './fixtures/data' );
	} );

	beforeEach( () => {
		originalData = cloneDeep( data.original );
		sitesList = SitesList();
		sitesList.initialize( originalData );
		initializedSites = sitesList.get();
	} );

	describe( 'initialization', () => {
		it( 'should create the correct number of sites', () => {
			assert.equal( initializedSites.length, originalData.length );
		} );

		it( 'should create Site objects', () => {
			forEach( initializedSites, site => {
				assert.instanceOf( site, Site )
			} );
		} );

		it( 'should set attributes properly', () => {
			const site = initializedSites[ 0 ];
			const origSite = originalData[ 0 ];

			forEach( origSite, ( value, prop ) => {
				assert.deepEqual( value, site[ prop ] );
			} );
		} );

		it( 'should add change handlers', () => {
			forEach( initializedSites, ( site ) => {
				assert.isDefined( site.listeners( 'change' ) );
			} );
		} );
	} );

	describe( 'updating', () => {
		let updatedData, originalList;

		before( () => {
			updatedData = cloneDeep( data.updated );
			originalList = sitesList.initialize( originalData );
		} );

		it( 'updating should not create new Site instances', () => {
			sitesList.update( updatedData );
			const updatedList = sitesList.get();

			forEach( originalList, ( site, index ) => {
				assert.strictEqual( site, updatedList[ index ] );
			} );
		} );

		it( 'should update attributes properly', () => {
			sitesList.update( updatedData );
			const site = sitesList.get()[ 0 ];
			const updatedSite = updatedData[ 0 ];

			forEach( updatedSite, ( updatedValue, prop ) => {
				assert.deepEqual( updatedValue, site[ prop ] );
			} );
		} );
	} );

	describe( 'change propagation', () => {
		it( 'should trigger change when site is updated', () => {
			const siteId = originalData[0].ID;
			const changeCallback = sinon.spy();

			sitesList.initialize( cloneDeep( data.original ) );
			sitesList.once( 'change', changeCallback );

			const site = sitesList.getSite( siteId );
			site.set( { description: 'Calypso rocks!' } );
			assert.isTrue( changeCallback.called );
		} );
	} );
} );
示例#18
0
describe( 'sync-handler', () => {
	useMockery( ( mockery ) => {
		mockery.registerMock( 'localforage', localforageMock );
		( { cacheIndex } = require( '../cache-index' ) );
		const handlerMock = ( params, callback ) => {
			const key = generateKey( params );
			callback( null, responseData[ key ] );
			return responseData[ key ];
		};
		( { SyncHandler, hasPaginationChanged, syncOptOut } = require( '../' ) );
		wpcom = new SyncHandler( handlerMock );
	} );

	beforeEach( () => {
		responseData = {};
		setLocalData( {} );
	} );

	it( 'should call callback with local response', () => {
		const {
			postListKey,
			postListParams,
			postListLocalRecord,
			postListResponseBody
		} = testData;
		const callback = spy();
		setLocalData( {
			[ postListKey ]: postListLocalRecord
		} );
		wpcom( postListParams, callback );
		expect( callback.calledWith( null, postListResponseBody ) );
	} );
	it( 'should call callback with request response', ( done ) => {
		const {
			postListKey,
			postListParams,
			postListResponseBody
		} = testData;
		const callback = spy();
		responseData[ postListKey ] = postListResponseBody;
		wpcom( postListParams, callback );
		defer( () => {
			expect( callback ).to.have.been.calledOnce;
			expect( callback.calledWith( null, postListResponseBody ) );
			done();
		} );
	} );
	it( 'should call callback twice with local and request responses', ( done ) => {
		const {
			postListKey,
			postListParams,
			postListLocalRecord,
			postListResponseBody,
			postListFreshResponseBody
		} = testData;
		const callback = spy();
		setLocalData( {
			[ postListKey ]: postListLocalRecord
		} );
		responseData[ postListKey ] = postListFreshResponseBody;
		wpcom( postListParams, callback );
		defer( () => {
			expect( callback ).to.have.been.calledTwice;
			expect( callback.calledWith( null, postListResponseBody ) );
			expect( callback.calledWith( null, postListFreshResponseBody ) );
			done();
		} );
	} );
	it( 'should store cacheIndex records with matching pageSeriesKey for paginated responses', ( done ) => {
		const {
			postListKey,
			postListNextPageKey,
			postListParams,
			postListNextPageParams,
			postListResponseBody,
			postListNextPageResponseBody,
		} = testData;
		responseData = {
			[ postListKey ]: postListResponseBody,
			[ postListNextPageKey ]: postListNextPageResponseBody,
		};
		wpcom( postListParams, () => {} );
		defer( () => {
			try {
				wpcom( postListNextPageParams, () => {} );
				defer( () => {
					try {
						const freshData = localforageMock.getLocalData();
						const firstRecord = freshData[ RECORDS_LIST_KEY ][ 0 ];
						const secondRecord = freshData[ RECORDS_LIST_KEY ][ 1 ];
						expect( firstRecord.key ).to.not.equal( secondRecord.key );
						expect( firstRecord.pageSeriesKey ).to.equal( secondRecord.pageSeriesKey );
						done();
					} catch ( err ) {
						done( err );
					}
				} );
			} catch ( err ) {
				done( err );
			}
		} );
	} );
	it( 'should call clearPageSeries when getting a response with an updated page_handle', ( done ) => {
		const {
			postListParams,
			postListLocalRecord,
			postListFreshResponseBody,
			postListKey,
		} = testData;
		setLocalData( { [ postListKey ]: postListLocalRecord } );
		responseData[ postListKey ] = postListFreshResponseBody;
		spy( cacheIndex, 'clearPageSeries' );
		wpcom( postListParams, () => {} );
		defer( () => {
			try {
				expect( cacheIndex.clearPageSeries.called ).to.be.true;
				cacheIndex.clearPageSeries.restore();
				done();
			} catch ( err ) {
				done( err );
			}
		} );
	} );

	describe( 'generateKey', () => {
		beforeEach( () => {
			responseData = {};
			setLocalData( {} );
		} );
		it( 'should return the same key for identical request', () => {
			const { postListParams } = testData;
			const secondRequest = Object.assign( {}, postListParams );
			const key1 = generateKey( postListParams );
			const key2 = generateKey( secondRequest );
			expect( typeof key1 ).to.equal( 'string' );
			expect( key1 ).to.equal( key2 );
		} );
		it( 'should return unique keys for different requests', () => {
			const { postListParams } = testData;
			const secondRequest = Object.assign( {}, postListParams, { query: '?filter=test' } );
			const key1 = generateKey( postListParams );
			const key2 = generateKey( secondRequest );
			expect( typeof key1 ).to.equal( 'string' );
			expect( key1 ).to.not.equal( key2 );
		} );
		it( 'should return the same key if parameters are in different order', () => {
			const { postListParams, postListDifferentOrderParams } = testData;
			const key1 = generateKey( postListParams );
			const key2 = generateKey( postListDifferentOrderParams );
			expect( typeof key1 ).to.equal( 'string' );
			expect( key1 ).to.equal( key2 );
		} );
	} );

	describe( 'hasPaginationChanged', () => {
		it( 'should return false if requestResponse has no page handle', () => {
			const { postListNoHandleResponseBody } = testData;
			const result = hasPaginationChanged( postListNoHandleResponseBody, null );
			expect( result ).to.equal( false );
		} );
		it( 'should return false for call with identical response', () => {
			const { postListResponseBody } = testData;
			const identicalResponse = Object.assign( {}, postListResponseBody );
			const result = hasPaginationChanged( postListResponseBody, identicalResponse );
			expect( result ).to.equal( false );
		} );
		it( 'should return true if page handle is different', () => {
			const { postListResponseBody, postListFreshResponseBody } = testData;
			const result = hasPaginationChanged( postListResponseBody, postListFreshResponseBody );
			expect( result ).to.equal( true );
		} );
		it( 'should return false with empty local response', () => {
			const { postListResponseBody } = testData;
			const result = hasPaginationChanged( postListResponseBody, null );
			expect( result ).to.equal( false );
		} );
	} );

	describe( 'syncOptOut', () => {
		let wpcomOptOut;
		before( () => {
			wpcomOptOut = syncOptOut( wpcomUndocumented( wpcom ) );
		} );

		it( 'should call callback with network response even when local response exists', ( done ) => {
			const {
				postListKey,
				postListSiteId,
				postListParams,
				postListNextPageLocalRecord,
				postListResponseBody
			} = testData;
			const callback = spy();
			setLocalData( {
				[ postListKey ]: postListNextPageLocalRecord
			} );
			responseData[ postListKey ] = postListResponseBody;

			wpcomOptOut.skipLocalSyncResult().site( postListSiteId ).postsList( querystring.parse( postListParams.query ), callback );

			defer( () => {
				expect( callback ).to.have.been.calledOnce;
				expect( callback ).to.have.been.calledWith( null, postListResponseBody );
				done();
			} );
		} );
	} );
} );
示例#19
0
文件: utils.js 项目: noxee/wp-calypso
describe( 'utils', function() {
	let postUtils;

	useFakeDom();

	useMockery( mockery => {
		mockery.registerMock( 'lib/wp', {
			me: () => ( {
				get: noop
			} )
		} );
	} );

	before( () => {
		postUtils = require( '../utils' );
	} );

	describe( '#getEditURL', function() {
		it( 'should return correct path type=post is supplied', function() {
			const url = postUtils.getEditURL( { ID: 123, type: 'post' }, { slug: 'en.blog.wordpress.com' } );
			assert( url === '/post/en.blog.wordpress.com/123' );
		} );

		it( 'should return correct path type=page is supplied', function() {
			const url = postUtils.getEditURL( { ID: 123, type: 'page' }, { slug: 'en.blog.wordpress.com' } );
			assert( url === '/page/en.blog.wordpress.com/123' );
		} );

		it( 'should return correct path when custom post type is supplied', function() {
			const url = postUtils.getEditURL( { ID: 123, type: 'jetpack-portfolio' }, { slug: 'en.blog.wordpress.com' } );
			assert( url === '/edit/jetpack-portfolio/en.blog.wordpress.com/123' );
		} );
	} );

	describe( '#getVisibility', function() {
		it( 'should return undefined when no post is supplied', function() {
			assert( postUtils.getVisibility() === undefined );
		} );

		it( 'should return public when password and private are not set', function() {
			assert( postUtils.getVisibility( {} ) === 'public' );
		} );

		it( 'should return private when post#status is private', function() {
			assert( postUtils.getVisibility( { status: 'private' } ) === 'private' );
		} );

		it( 'should return password when post#password is set', function() {
			assert( postUtils.getVisibility( { password: '******' } ) === 'password' );
		} );
	} );

	describe( '#isPrivate', function() {
		it( 'should return undefined when no post is supplied', function() {
			assert( postUtils.isPrivate() === undefined );
		} );

		it( 'should return true when post.status is private', function() {
			assert( postUtils.isPrivate( { status: 'private' } ) );
		} );

		it( 'should return false when post.status is not private', function() {
			assert( ! postUtils.isPrivate( { status: 'draft' } ) );
		} );
	} );

	describe( '#isPublished', function() {
		it( 'should return undefined when no post is supplied', function() {
			assert( postUtils.isPublished() === undefined );
		} );

		it( 'should return true when post.status is private', function() {
			assert( postUtils.isPublished( { status: 'private' } ) );
		} );

		it( 'should return true when post.status is publish', function() {
			assert( postUtils.isPublished( { status: 'publish' } ) );
		} );

		it( 'should return false when post.status is not publish or private', function() {
			assert( ! postUtils.isPublished( { status: 'draft' } ) );
		} );
	} );

	describe( '#isPending', function() {
		it( 'should return undefined when no post is supplied', function() {
			assert( postUtils.isPending() === undefined );
		} );

		it( 'should return true when post.status is pending', function() {
			assert( postUtils.isPending( { status: 'pending' } ) );
		} );

		it( 'should return false when post.status is not pending', function() {
			assert( ! postUtils.isPending( { status: 'draft' } ) );
		} );
	} );

	describe( '#isBackDatedPublished', function() {
		it( 'should return false when no post is supplied', function() {
			assert( ! postUtils.isBackDatedPublished() );
		} );

		it( 'should return false when status !== future', function() {
			assert( ! postUtils.isBackDatedPublished( { status: 'draft' } ) );
		} );

		it( 'should return false when status === future and date is in future', function() {
			const tenMinutes = 1000 * 60;
			const postDate = Date.now() + tenMinutes;

			assert( ! postUtils.isBackDatedPublished( { status: 'future', date: postDate } ) );
		} );

		it( 'should return true when status === future and date is in the past', function() {
			const tenMinutes = 1000 * 60;
			const postDate = Date.now() - tenMinutes;

			assert( postUtils.isBackDatedPublished( { status: 'future', date: postDate } ) );
		} );
	} );

	describe( '#removeSlug', function() {
		it( 'should return undefined when no path is supplied', function() {
			assert( postUtils.removeSlug() === undefined );
		} );

		it( 'should strip slug on post URL', function() {
			const noSlug = postUtils.removeSlug( 'https://en.blog.wordpress.com/2015/08/26/new-action-bar/' );
			assert( noSlug === 'https://en.blog.wordpress.com/2015/08/26/' );
		} );

		it( 'should strip slug on page URL', function() {
			const noSlug = postUtils.removeSlug( 'https://en.blog.wordpress.com/a-test-page/' );
			assert( noSlug === 'https://en.blog.wordpress.com/' );
		} );
	} );

	describe( '#getPermalinkBasePath', function() {
		it( 'should return undefined when no post is supplied', function() {
			assert( postUtils.getPermalinkBasePath() === undefined );
		} );

		it( 'should return post.URL when post is published', function() {
			const path = postUtils.getPermalinkBasePath( {
				status: 'publish',
				URL: 'https://en.blog.wordpress.com/2015/08/26/new-action-bar/'
			} );
			assert( path === 'https://en.blog.wordpress.com/2015/08/26/' );
		} );

		it( 'should use permalink_URL when not published and present', function() {
			const path = postUtils.getPermalinkBasePath( {
				other_URLs: { permalink_URL: 'http://zo.mg/a/permalink/%post_name%/' },
				URL: 'https://en.blog.wordpress.com/2015/08/26/new-action-bar/'
			} );
			assert( path === 'http://zo.mg/a/permalink/' );
		} );
	} );

	describe( '#getPagePath', function() {
		it( 'should return undefined when no post is supplied', function() {
			assert( postUtils.getPagePath() === undefined );
		} );

		it( 'should return post.URL without slug when page is published', function() {
			const path = postUtils.getPagePath( {
				status: 'publish',
				URL: 'http://zo.mg/a/permalink/'
			} );
			assert( path === 'http://zo.mg/a/' );
		} );

		it( 'should use permalink_URL when not published and present', function() {
			const path = postUtils.getPagePath( {
				status: 'draft',
				other_URLs: { permalink_URL: 'http://zo.mg/a/permalink/%post_name%/' }
			} );
			assert( path === 'http://zo.mg/a/permalink/' );
		} );
	} );

	describe( '#getFeaturedImageId()', function() {
		it( 'should return undefined when no post is specified', function() {
			assert( postUtils.getFeaturedImageId() === undefined );
		} );

		it( 'should return a non-URL featured_image property', function() {
			const id = postUtils.getFeaturedImageId( {
				featured_image: 'media-1',
				post_thumbnail: {
					ID: 1
				}
			} );

			assert( id === 'media-1' );
		} );

		it( 'should return a `null` featured_image property', function() {
			// This describes the behavior of unassigning a featured image
			// from the current post
			const id = postUtils.getFeaturedImageId( {
				featured_image: null,
				post_thumbnail: {
					ID: 1
				}
			} );

			assert( id === null );
		} );

		it( 'should fall back to post thumbnail object ID if exists, if featured_image is URL', function() {
			const id = postUtils.getFeaturedImageId( {
				featured_image: 'https://example.com/image.png',
				post_thumbnail: {
					ID: 1
				}
			} );

			assert( id === 1 );
		} );

		it( 'should return undefined if featured_image is URL and post thumbnail object doesn\'t exist', function() {
			const id = postUtils.getFeaturedImageId( {
				featured_image: 'https://example.com/image.png'
			} );

			assert( id === undefined );
		} );
	} );
} );
示例#20
0
describe( 'StatsParser', () => {
	let statsParser, data;

	useMockery();
	useFakeDom();

	before( () => {
		statsParser = require( '../stats-parser' )();
		data = require( './fixtures/data' );
	} );

	describe( 'stat types', () => {
		it( 'should have a statsClicks function', () => {
			assert.isFunction( statsParser.statsClicks, 'it should have a statsClick function' );
		} );

		it( 'should have a statsTags function', () => {
			assert.isFunction( statsParser.statsTags, 'it should have a statsTag function' );
		} );
	} );

	describe( 'statsClicks', () => {
		it( 'should parse a clicks response properly', () => {
			// we have to pass in some context to calculate start of period on this call
			const mockContext = { options: { period: 'day', date: '2014-09-12' } };
			const response = statsParser.statsClicks.call( mockContext, data.successResponses.statsClicks.body );

			assert.lengthOf( response.data, 10 );
			assert.equal( response.data[ 0 ].label, 'example.com' );
			assert.equal( response.data[ 0 ].value, 126 );
			assert.isNull( response.data[ 0 ].children );
			assert.isNull( response.data[ 0 ].icon );

			assert.lengthOf( response.data[ 2 ].children, 3 ); // check a record with children
		} );
	} );

	describe( 'statsTags', () => {
		it( 'should parse tags response properly', () => {
			const response = statsParser.statsTags( data.successResponses.statsTags.body );
			const item = response.data[ 2 ];

			assert.lengthOf( response.data, 9 );

			// tags labels are arrays of labels, right?
			assert.isArray( item.label, 'Label should be array' );
			assert.deepEqual( map( item.label, 'label' ), [ 'supertag', 'supertag-transition' ] );
			assert.deepEqual( map( item.label, 'labelIcon' ), [ 'tag', 'tag' ] );
			assert.isNull( item.label[0].link );
			assert.equal( item.value, 480 );
		} );
	} );

	describe( 'statsCountryViews', () => {
		it( 'should parse countryViews payload properly', () => {
			const mockContext = { options: { period: 'day', date: '2014-09-12' } };
			const response = statsParser.statsCountryViews.call( mockContext, data.successResponses.statsCountryViews.body );
			const item = response.data[ 0 ];

			assert.lengthOf( response.data, 5 );
			assert.equal( item.label, 'United States' );
			assert.equal( item.value, 54 );
		} );
	} );
} );
示例#21
0
describe( 'wpcom-api', () => {
	let dispatch, settingsModule;

	useSandbox( sandbox => {
		dispatch = sandbox.spy();
	} );

	useMockery( () => {
		mockery.registerMock( 'lib/user', () => ( {
			fetch() {}
		} ) );
		settingsModule = require( '../' );
	} );

	describe( 'user settings request', () => {
		describe( '#requestUserSettings', () => {
			it( 'should dispatch HTTP GET request to me/settings endpoint', () => {
				const action = { type: 'DUMMY' };

				settingsModule.requestUserSettings( { dispatch }, action );

				expect( dispatch ).to.have.been.calledOnce;
				expect( dispatch ).to.have.been.calledWith( http( {
					apiVersion: '1.1',
					method: 'GET',
					path: '/me/settings',
				}, action ) );
			} );
		} );

		describe( '#storeFetchedUserSettings', () => {
			it( 'should dispatch user settings update', () => {
				const action = { type: 'DUMMY' };

				settingsModule.storeFetchedUserSettings( { dispatch }, action, {
					language: 'qix',
				} );

				expect( dispatch ).to.have.been.calledOnce;
				expect( dispatch ).to.have.been.calledWith( updateUserSettings( {
					language: 'qix',
				} ) );
			} );

			it( 'should decode HTML entities returned in some fields of HTTP response', () => {
				const action = { type: 'DUMMY' };

				settingsModule.storeFetchedUserSettings( { dispatch }, action, {
					display_name: 'baz &amp; qix',
					description: 'foo &amp; bar',
					user_URL: 'http://example.com?a=b&amp;c=d',
				} );

				expect( dispatch ).to.have.been.calledWith( updateUserSettings( {
					display_name: 'baz & qix',
					description: 'foo & bar',
					user_URL: 'http://example.com?a=b&c=d',
				} ) );
			} );
		} );
	} );

	describe( 'user settings save', () => {
		describe( '#saveUserSettings', () => {
			it( 'should dispatch POST request to me/settings using unsavedSettings from state', () => {
				const getState = () => ( {
					userSettings: {
						settings: { foo: 'bar' },
						unsavedSettings: { foo: 'baz' }
					}
				} );
				const action = { type: 'DUMMY' };

				settingsModule.saveUserSettings( { dispatch, getState }, action, null );

				expect( dispatch ).to.have.been.calledOnce;
				expect( dispatch ).to.have.been.calledWith( http( {
					apiVersion: '1.1',
					method: 'POST',
					path: '/me/settings',
					body: { foo: 'baz' }
				}, action ) );
			} );

			it( 'should dispatch POST request to me/settings using explicit settingsOverride', () => {
				const getState = () => ( {} );
				const action = {
					type: 'DUMMY',
					settingsOverride: { foo: 'baz' }
				};

				settingsModule.saveUserSettings( { dispatch, getState }, action, null );

				expect( dispatch ).to.have.been.calledOnce;
				expect( dispatch ).to.have.been.calledWith( http( {
					apiVersion: '1.1',
					method: 'POST',
					path: '/me/settings',
					body: { foo: 'baz' }
				}, action ) );
			} );

			it( 'should not dispatch any HTTP request when there are no unsaved settings', () => {
				const getState = () => ( {
					userSettings: {
						settings: {},
						unsavedSettings: {}
					}
				} );
				const action = { type: 'DUMMY' };

				settingsModule.saveUserSettings( { dispatch, getState }, action, null );

				expect( dispatch ).to.not.have.been.called;
			} );
		} );

		describe( '#finishUserSettingsSave', () => {
			it( 'should dispatch user settings update and clear all unsaved settings on full save', () => {
				const action = { type: 'DUMMY' };

				settingsModule.finishUserSettingsSave( { dispatch }, action, {
					language: 'qix',
				} );

				expect( dispatch ).to.have.been.calledTwice;
				expect( dispatch ).to.have.been.calledWith( updateUserSettings( {
					language: 'qix',
				} ) );
				expect( dispatch ).to.have.been.calledWith( clearUnsavedUserSettings() );
			} );

			it( 'should dispatch user settings update and clear only one unsaved setting on partial save', () => {
				const data = {
					language: 'qix',
				};
				const action = { type: 'DUMMY', settingsOverride: data };

				settingsModule.finishUserSettingsSave( { dispatch }, action, data );

				expect( dispatch ).to.have.been.calledTwice;
				expect( dispatch ).to.have.been.calledWith( updateUserSettings( {
					language: 'qix'
				} ) );
				expect( dispatch ).to.have.been.calledWith( clearUnsavedUserSettings( [
					'language'
				] ) );
			} );

			it( 'should decode HTML entities returned in some fields of HTTP response', () => {
				const action = { type: 'DUMMY' };

				settingsModule.finishUserSettingsSave( { dispatch }, action, {
					display_name: 'baz &amp; qix',
					description: 'foo &amp; bar',
					user_URL: 'http://example.com?a=b&amp;c=d',
				} );

				expect( dispatch ).to.have.been.calledWith( updateUserSettings( {
					display_name: 'baz & qix',
					description: 'foo & bar',
					user_URL: 'http://example.com?a=b&c=d',
				} ) );
			} );
		} );
	} );
} );
示例#22
0
describe( 'index', function() {
	let React,
		ReactDom,
		ReactInjection,
		DomainList,
		TestUtils,
		noticeTypes,
		component,
		sandbox;

	useSandbox( newSandbox => sandbox = newSandbox );
	useFakeDom.withContainer();
	useMockery( mockery => {
		require( 'test/helpers/mocks/component-classes' )( mockery );
		require( 'test/helpers/mocks/component-tip' )( mockery );
		require( 'test/helpers/mocks/data-poller' )( mockery );
		mockery.registerMock( 'components/section-nav', EmptyComponent );
	} );
	useI18n();

	before( () => {
		React = require( 'react' );
		ReactDom = require( 'react-dom' );
		TestUtils = require( 'react-addons-test-utils' );

		noticeTypes = require( '../constants' );

		ReactInjection = require( 'react/lib/ReactInjection' );
		ReactInjection.Class.injectMixin( require( 'lib/mixins/i18n' ).mixin );

		DomainList = require( '../' ).List;
	} );

	const selectedSite = deepFreeze( {
		slug: 'example.com',
		ID: 1
	} );

	const defaultProps = deepFreeze( {
		domains: {
			hasLoadedFromServer: true,
			list: [
				{ name: 'domain0.com', isPrimary: false },
				{ name: 'example.com', isPrimary: true }
			]
		},
		cart: {},
		context: {
			path: ''
		},
		products: {},
		selectedDomainName: 'example.com',
		selectedSite: selectedSite,
		sites: {
			getSelectedSite() {
				return selectedSite;
			}
		},
		sitePlans: {}
	} );

	function renderWithProps( props = defaultProps ) {
		return ReactDom.render( <DomainList { ...props } />, useFakeDom.getContainer() );
	}

	describe( 'regular cases', function() {
		beforeEach( function() {
			component = renderWithProps();
		} );

		afterEach( function() {
			ReactDom.unmountComponentAtNode( useFakeDom.getContainer() );
		} );

		it( 'should list two domains', () => {
			assert.equal( [].slice.call( ReactDom.findDOMNode( component ).querySelectorAll( '.domain-management-list-item' ) ).length, 2 );
		} );
	} );

	describe( 'setting primary domain', () => {
		describe( 'when not enabled', () => {
			beforeEach( () => {
				component = renderWithProps();
			} );

			afterEach( function() {
				ReactDom.unmountComponentAtNode( useFakeDom.getContainer() );
			} );

			it( 'should show "Change Primary Domain" button', () => {
				assert( ReactDom.findDOMNode( component ).querySelector( '.domain-management-list__change-primary-button' ) );
			} );

			it( 'should enable upon clicking the button', () => {
				const button = ReactDom.findDOMNode( component ).querySelector( '.domain-management-list__change-primary-button' );
				TestUtils.Simulate.click( button );
				assert( component.state.changePrimaryDomainModeEnabled );
			} );
		} );

		describe( 'when enabled', () => {
			beforeEach( () => {
				component = renderWithProps();
				const button = ReactDom.findDOMNode( component ).querySelector( '.domain-management-list__change-primary-button' );
				TestUtils.Simulate.click( button );
			} );

			afterEach( function() {
				ReactDom.unmountComponentAtNode( useFakeDom.getContainer() );
			} );

			it( 'should show the cancel button', () => {
				assert( ReactDom.findDOMNode( component.refs.cancelChangePrimaryButton ) );
			} );

			it( 'should disable upon clicking cancel button', () => {
				const button = ReactDom.findDOMNode( component.refs.cancelChangePrimaryButton );
				TestUtils.Simulate.click( button );
				assert( ! component.state.changePrimaryDomainModeEnabled );
			} );

			it( 'should set the primaryDomainIndex correctly', () => {
				const primaryDomainIndex = 1; // from data above
				assert.equal( component.state.primaryDomainIndex, primaryDomainIndex );
			} );

			describe( '#handleUpdatePrimaryDomain', () => {
				let setPrimaryDomainStub,
					setPrimaryDomainResolve,
					setPrimaryDomainReject;
				beforeEach( () => {
					setPrimaryDomainStub = sandbox.stub( component, 'setPrimaryDomain' ).returns( new Promise( ( resolve, reject ) => {
						setPrimaryDomainResolve = resolve;
						setPrimaryDomainReject = reject;
					} ) );
				} );
				it( 'should not call setPrimaryDomain with on trying to set the already primary domain', () => {
					component.handleUpdatePrimaryDomain( 1, defaultProps.domains.list[ 1 ] );
					setPrimaryDomainResolve();
					assert( ! component.state.settingPrimaryDomain );
					assert( ! component.state.changePrimaryDomainModeEnabled );
					assert( ! setPrimaryDomainStub.called );
				} );

				it( 'should call setPrimaryDomain with a domain name', ( done ) => {
					component.handleUpdatePrimaryDomain( 0, defaultProps.domains.list[ 0 ] );
					assert( component.state.settingPrimaryDomain );
					assert( component.state.primaryDomainIndex === 0 );
					assert( setPrimaryDomainStub.calledWith( defaultProps.domains.list[ 0 ].name ),
						'#setPrimaryDomain should be called with the domain name' );
					setPrimaryDomainResolve();
					setTimeout( () => {
						assert( ! component.state.settingPrimaryDomain, 'Setting Primary Domain should be false' );
						assert( ! component.changePrimaryDomainModeEnabled );
						assert.equal( component.state.notice.type, noticeTypes.PRIMARY_DOMAIN_CHANGE_SUCCESS );
						assert.equal( component.state.notice.previousDomainName, defaultProps.domains.list[ 1 ].name );
						done();
					}, 0 );
				} );

				it( 'should handle errors and revert the optimistic updates', ( done ) => {
					component.handleUpdatePrimaryDomain( 0, defaultProps.domains.list[ 0 ] );
					setPrimaryDomainReject();
					setTimeout( () => {
						assert( ! component.state.settingPrimaryDomain );
						assert( component.state.changePrimaryDomainModeEnabled );
						assert.equal( component.state.primaryDomainIndex, 1 );
						assert.equal( component.state.notice.type, noticeTypes.PRIMARY_DOMAIN_CHANGE_FAIL );
						done();
					}, 0 );
				} );
			} );
		} );

		describe( 'when less than 2 domains', () => {
			beforeEach( () => {
				const oneDomain = deepFreeze( {
					domains: {
						hasLoadedFromServer: true,
						list: [
							{ name: 'example.com', isPrimary: true }
						]
					}
				} );
				const propsWithOneDomain = deepFreeze( Object.assign( {}, defaultProps, oneDomain ) );
				component = renderWithProps( propsWithOneDomain );
			} );

			it( 'should not show "Change Primary Domain" button', () => {
				const button = ReactDom.findDOMNode( component ).querySelector( '.domain-management-list__change-primary-button' );
				assert( button === null );
			} );
		} );
	} );
} );
示例#23
0
describe( 'utils', function() {
	var flows, utils;

	useFilesystemMocks( __dirname );
	useI18n();
	useMockery( ( mockery ) => {
		mockery.registerMock( 'lib/abtest', {
			abtest: () => ''
		} );
		flows = require( 'signup/config/flows' );
		utils = require( '../utils' );
	} );

	describe( 'getLocale', function() {
		it( 'should find the locale anywhere in the params', function() {
			assert.equal( utils.getLocale( { lang: 'fr' } ), 'fr' );
			assert.equal( utils.getLocale( { stepName: 'fr' } ), 'fr' );
			assert.equal( utils.getLocale( { flowName: 'fr' } ), 'fr' );
		} );

		it( 'should return undefined if no locale is present in the params', function() {
			assert.equal( utils.getLocale( {
				stepName: 'theme-selection',
				flowName: 'flow-one'
			} ), undefined );
		} );
	} );

	describe( 'getStepName', function() {
		it( 'should find the step name in either the stepName or flowName fragment', function() {
			assert.equal( utils.getStepName( { stepName: 'user' } ), 'user' );
			assert.equal( utils.getStepName( { flowName: 'user' } ), 'user' );
		} );

		it( 'should return undefined if no step name is found', function() {
			assert.equal( utils.getStepName( { flowName: 'account' } ), undefined );
		} );
	} );

	describe( 'getFlowName', function() {
		afterEach( function() {
			flows.filterFlowName = null;
		} );

		it( 'should find the flow name in the flowName fragment if present', function() {
			assert.equal( utils.getFlowName( { flowName: 'other' } ), 'other' );
		} );

		it( 'should return the default flow if the flow is missing', function() {
			assert.equal( utils.getFlowName( {} ), 'main' );
		} );

		it( 'should return the result of filterFlowName if it is a function and the flow is missing', function() {
			flows.filterFlowName = sinon.stub().returns( 'filtered' );
			assert.equal( utils.getFlowName( {} ), 'filtered' );
		} );

		it( 'should return the result of filterFlowName if it is a function and the flow is not valid', function() {
			flows.filterFlowName = sinon.stub().returns( 'filtered' );
			assert.equal( utils.getFlowName( { flowName: 'invalid' } ), 'filtered' );
		} );

		it( 'should return the result of filterFlowName if it is a function and the requested flow is present', function() {
			flows.filterFlowName = sinon.stub().returns( 'filtered' );
			assert.equal( utils.getFlowName( { flowName: 'other' } ), 'filtered' );
		} );

		it( 'should return the passed flow if the result of filterFlowName is not valid', function() {
			flows.filterFlowName = sinon.stub().returns( 'foobar' );
			assert.equal( utils.getFlowName( { flowName: 'other' } ), 'other' );
		} );

		it( 'should call filterFlowName with the default flow if it is a function and the flow is not valid', function() {
			flows.filterFlowName = sinon.stub().returns( 'filtered' );
			utils.getFlowName( { flowName: 'invalid' } );
			assert( flows.filterFlowName.calledWith( 'main' ) );
		} );

		it( 'should call filterFlowName with the requested flow if it is a function and the flow is valid', function() {
			flows.filterFlowName = sinon.stub().returns( 'filtered' );
			utils.getFlowName( { flowName: 'other' } );
			assert( flows.filterFlowName.calledWith( 'other' ) );
		} );
	} );

	describe( 'getValidPath', function() {
		it( 'should redirect to the default if no flow is present', function() {
			assert.equal( utils.getValidPath( {} ), '/start/user' );
		} );

		it( 'should redirect to the current flow default if no step is present', function() {
			assert.equal( utils.getValidPath( { flowName: 'account' } ), '/start/account/user' );
		} );

		it( 'should redirect to the default flow if the flow is the default', function() {
			assert.equal( utils.getValidPath( { flowName: 'main' } ), '/start/user' );
		} );

		it( 'should redirect invalid steps to the default flow if no flow is present', function() {
			assert.equal( utils.getValidPath( {
				stepName: 'fr',
				stepSectionName: 'fr'
			} ), '/start/user/fr' );
		} );

		it( 'should preserve a valid locale to the default flow if one is specified', function() {
			assert.equal( utils.getValidPath( {
				stepName: 'fr',
				stepSectionName: 'abc'
			} ), '/start/user/abc/fr' );
		} );

		it( 'should redirect invalid steps to the current flow default', function() {
			assert.equal( utils.getValidPath( {
				flowName: 'account',
				stepName: 'fr',
				stepSectionName: 'fr'
			} ), '/start/account/user/fr' );
		} );

		it( 'should preserve a valid locale if one is specified', function() {
			assert.equal( utils.getValidPath( {
				flowName: 'account',
				stepName: 'fr',
				stepSectionName: 'abc'
			} ), '/start/account/user/abc/fr' );
		} );

		it( 'should handle arbitrary step section names', function() {
			var randomStepSectionName = 'random-step-section-' + Math.random();

			assert.equal( utils.getValidPath( {
				flowName: 'account',
				stepName: 'user',
				stepSectionName: randomStepSectionName,
				lang: 'fr'
			} ), '/start/account/user/' + randomStepSectionName + '/fr' );
		} );

		it( 'should handle arbitrary step section names in the default flow', function() {
			var randomStepSectionName = 'random-step-section-' + Math.random();

			assert.equal( utils.getValidPath( {
				stepName: 'user',
				stepSectionName: randomStepSectionName,
				lang: 'fr'
			} ), '/start/user/' + randomStepSectionName + '/fr' );
		} );
	} );

	describe( 'getValueFromProgressStore', function() {
		const testStore = [ { stepName: 'empty' }, { stepName: 'site', site: 'calypso' } ];
		const config = {
			stepName: 'site',
			fieldName: 'site',
			signupProgressStore: testStore
		};

		it( 'should return the value of the field if it exists', function() {
			assert.equal( utils.getValueFromProgressStore( config ), 'calypso' );
		} );

		it( 'should return null if the field is not present', function() {
			delete testStore[ 1 ].site;
			assert.equal( utils.getValueFromProgressStore( config ), null );
		} );
	} );

	describe( 'mergeFormWithValue', function() {
		const config = {
			fieldName: 'username',
			fieldValue: 'calypso'
		};

		it( 'should return the form with the field added if the field doesn\'t have a value', function() {
			const form = { username: {} };
			config.form = form;
			assert.deepEqual( utils.mergeFormWithValue( config ), {
				username: { value: 'calypso' }
			} );
		} );

		it( 'should return the form unchanged if there is already a value in the form', function() {
			const form = { username: { value: 'wordpress' } };
			config.form = form;
			assert.equal( utils.mergeFormWithValue( config ), form );
		} );
	} );
} );
示例#24
0
describe( '#signupStep User', () => {
	let User, testElement, rendered, EMPTY_COMPONENT;

	useFakeDom();

	useMockery( ( mockery ) => {
		EMPTY_COMPONENT = require( 'test/helpers/react/empty-component' );

		mockery.registerMock( 'lib/abtest', noop );
		mockery.registerMock( 'lib/analytics', {} );
		mockery.registerMock( 'components/signup-form', EMPTY_COMPONENT );
		mockery.registerMock( 'signup/step-wrapper', EMPTY_COMPONENT );

		mockery.registerMock( 'signup/utils', {
			getFlowSteps: function( flow ) {
				let flowSteps = null;

				if ( 'userAsFirstStepInFlow' === flow ) {
					flowSteps = [ 'user' ];
				} else {
					flowSteps = [ 'theme', 'domains', 'user' ];
				}

				return flowSteps;
			},
			getNextStepName: identity,
			getStepUrl: identity,
			getPreviousStepName: identity
		} );
	} );

	before( () => {
		User = require( '../' );
		User.prototype.translate = ( string ) => string;
	} );

	it( 'should show community subheader text if User step is first in the flow', () => {
		testElement = React.createElement( User, {
			subHeaderText: 'first subheader message',
			flowName: 'userAsFirstStepInFlow'
		} );
		rendered = TestUtils.renderIntoDocument( testElement );

		expect( rendered.state.subHeaderText ).to.equal( 'Welcome to the wonderful WordPress.com community' );
	} );

	it( 'should show provided subheader text if User step is not first in the flow', () => {
		testElement = React.createElement( User, {
			subHeaderText: 'test subheader message',
			flowName: 'someOtherFlow'
		} );
		rendered = TestUtils.renderIntoDocument( testElement );

		expect( rendered.state.subHeaderText ).to.equal( 'test subheader message' );
	} );

	describe( '#updateComponentProps', () => {
		let node, spyComponentProps, component;

		beforeEach( () => {
			node = document.createElement( 'div' );

			spyComponentProps = sinon.spy( User.prototype, 'componentWillReceiveProps' );

			const element = React.createElement( User, {
				subHeaderText: 'test subheader message',
				flowName: 'someOtherFlow'
			} );
			component = ReactDOM.render( element, node );
		} );

		afterEach( () => {
			User.prototype.componentWillReceiveProps.restore();
		} );

		it( 'should show community subheader text when new flow has user as first step', () => {
			const testProps = {
				subHeaderText: 'My test message',
				flowName: 'userAsFirstStepInFlow'
			};

			expect( spyComponentProps.calledOnce ).to.equal( false );

			ReactDOM.render( React.createElement( User, testProps ), node );

			expect( spyComponentProps.calledOnce ).to.equal( true );
			expect( component.state.subHeaderText ).to.equal( 'Welcome to the wonderful WordPress.com community' );
		} );

		it( 'should show provided subheader text when new flow doesn\'t have user as first step', () => {
			const testProps = {
				subHeaderText: 'My test message',
				flowName: 'another test message test'
			};

			expect( spyComponentProps.calledOnce ).to.equal( false );

			ReactDOM.render( React.createElement( User, testProps ), node );

			expect( spyComponentProps.calledOnce ).to.equal( true );
			expect( component.state.subHeaderText ).to.equal( 'My test message' );
		} );
	} );
} );
示例#25
0
describe( 'utils', () => {
	const currentState = deepFreeze( {
			test: [ 'one', 'two', 'three' ]
		} ),
		actionSerialize = { type: SERIALIZE },
		actionDeserialize = { type: DESERIALIZE };
	let createReducer, reducer;

	useMockery( ( mockery ) => {
		mockery.registerMock( 'lib/warn', noop );

		createReducer = require( 'state/utils' ).createReducer;
	} );

	describe( '#createReducer()', () => {
		context( 'only default behavior', () => {
			before( () => {
				reducer = createReducer();
			} );

			it( 'should return a function', () => {
				expect( reducer ).to.be.a.function;
			} );

			it( 'should return initial state when invalid action passed', () => {
				const invalidAction = {};

				expect(
					reducer( currentState, invalidAction )
				).to.be.deep.equal( currentState );
			} );

			it( 'should return initial state when unknown action type passed', () => {
				const unknownAction = {
					type: 'UNKNOWN'
				};

				expect(
					reducer( currentState, unknownAction )
				).to.be.deep.equal( currentState );
			} );

			it( 'should return default null state when serialize action type passed', () => {
				expect(
					reducer( currentState, actionSerialize )
				).to.be.null;
			} );

			it( 'should return default null state when deserialize action type passed', () => {
				expect(
					reducer( currentState, actionDeserialize )
				).to.be.null;
			} );
		} );

		context( 'with reducers and default state provided', () => {
			const initialState = {},
				TEST_ADD = 'TEST_ADD';

			before( () => {
				reducer = createReducer( initialState, {
					[ TEST_ADD ]: ( state, action ) => {
						return {
							test: [ ...state.test, action.value ]
						};
					}
				} );
			} );

			it( 'should return default {} state when SERIALIZE action type passed', () => {
				expect(
					reducer( currentState, actionSerialize )
				).to.be.equal( initialState );
			} );

			it( 'should return default {} state when DESERIALIZE action type passed', () => {
				expect(
					reducer( currentState, actionDeserialize )
				).to.be.equal( initialState );
			} );

			it( 'should add new value to test array when acc action passed', () => {
				const addAction = {
					type: TEST_ADD,
					value: 'four'
				};

				const newState = reducer( currentState, addAction );

				expect( newState ).to.not.equal( currentState );
				expect( newState ).to.be.eql( {
					test: [ 'one', 'two', 'three', 'four' ]
				} );
			} );
		} );

		context( 'with schema provided', () => {
			const initialState = {};

			before( () => {
				reducer = createReducer( initialState, {}, testSchema );
			} );

			it( 'should return initial state when serialize action type passed', () => {
				expect(
					reducer( currentState, actionSerialize )
				).to.be.deep.equal( currentState );
			} );

			it( 'should return initial state when valid initial state and deserialize action type passed', () => {
				expect(
					reducer( currentState, actionDeserialize )
				).to.be.deep.equal( currentState );
			} );

			it( 'should return default state when invalid initial state and deserialize action type passed', () => {
				expect(
					reducer( { invalid: 'state' }, actionDeserialize )
				).to.be.deep.equal( initialState );
			} );
		} );

		context( 'with default actions overrides', () => {
			const overriddenState = { overridden: 'state' };

			before( () => {
				reducer = createReducer( null, {
					[ SERIALIZE ]: () => overriddenState,
					[ DESERIALIZE ]: () => overriddenState
				} );
			} );

			it( 'should return overridden state when serialize action type passed', () => {
				expect(
					reducer( currentState, actionSerialize )
				).to.be.deep.equal( overriddenState );
			} );

			it( 'should return overridden state when deserialize action type passed', () => {
				expect(
					reducer( currentState, actionDeserialize )
				).to.be.deep.equal( overriddenState );
			} );
		} );

		it( 'should cache the serialize result on custom serialization behavior', () => {
			const monitor = stub().returnsArg( 0 );

			reducer = createReducer( [], {
				[ SERIALIZE ]: monitor,
				TEST_ADD: ( state ) => [ ...state, state.length ]
			}, testSchema );

			let state;
			state = reducer( state, { type: SERIALIZE } );
			state = reducer( state, { type: SERIALIZE } );
			state = reducer( state, { type: 'TEST_ADD' } );
			state = reducer( state, { type: SERIALIZE } );
			state = reducer( state, { type: SERIALIZE } );
			state = reducer( state, { type: 'TEST_ADD' } );
			state = reducer( state, { type: SERIALIZE } );

			expect( monitor ).to.have.been.calledThrice;
			expect( state ).to.eql( [ 0, 1 ] );
		} );
	} );
} );
示例#26
0
describe( 'helper', () => {
	const { discoverPost } = fixtures;
	let helper;
	useMockery( mockery => {
		mockery.registerMock( 'config', () => fixtures.discoverSiteId );
		mockery.registerMock( 'lib/user/utils', { getLocaleSlug: () => 'en' } );
	} );

	useFakeDom();

	before( () => {
		helper = require( '../helper' );
	} );

	describe( 'isDiscoverPost', () => {
		it( 'returns true if discover metadata is present', () => {
			assert.isTrue( helper.isDiscoverPost( discoverPost ) );
		} );

		it( 'returns true if the site id is discovery_blog_id', () => {
			const withoutMetadata = omit( fixtures.discoverSiteFormat, 'discover_metadata' );
			assert.isTrue( helper.isDiscoverPost( withoutMetadata ) );
		} );

		it( 'returns false if the site is not disover or discover metadata is not present', () => {
			assert.isFalse( helper.isDiscoverPost( fixtures.nonDiscoverPost ) );
		} );

		it( 'returns false if the post is undefined', () => {
			assert.isFalse( helper.isDiscoverPost() );
		} );
	} );

	describe( 'isDiscoverSitePick', () => {
		it( 'returns true if the post is a site pick', () => {
			assert.isTrue( helper.isDiscoverSitePick( fixtures.discoverSiteFormat ) );
		} );

		it( 'returns false if the post is not a site pick', () => {
			assert.isFalse( helper.isDiscoverSitePick( discoverPost ) );
		} );

		it( 'returns false if the post is undefined', () => {
			assert.isFalse( helper.isDiscoverSitePick() );
		} );
	} );

	describe( 'isInternalDiscoverPost', () => {
		it( 'returns true if the post is internal to wpcom', () => {
			assert.isTrue( helper.isInternalDiscoverPost( discoverPost ) );
		} );

		it( 'returns false if the post is not internal to wpcom', () => {
			assert.isFalse( helper.isInternalDiscoverPost( fixtures.externalDiscoverPost ) );
		} );
	} );

	describe( 'getSiteUrl', () => {
		it( 'returns a reader route if the post is internal', () => {
			assert.match( helper.getSiteUrl( discoverPost ), /^\/read\/blogs/ );
		} );

		it( 'returns the permalink if the post is not internal', () => {
			const permalink = get( fixtures.externalDiscoverPost, 'discover_metadata.permalink' );
			assert.equal( permalink, helper.getSiteUrl( fixtures.externalDiscoverPost ) );
		} );

		it( 'returns undefined if the post is not a discover post', () => {
			assert.isUndefined( helper.getSiteUrl( fixtures.nonDiscoverPost ) );
		} );
	} );

	describe( 'hasSource', () => {
		it( 'returns true if the post is not a site pick', () => {
			assert.isTrue( helper.hasSource( discoverPost ) );
		} );

		it( 'returns false if the post is a site pick', () => {
			assert.isFalse( helper.hasSource( fixtures.discoverSiteFormat ) );
		} );

		it( 'returns false if the post is undefined', () => {
			assert.isFalse( helper.hasSource() );
		} );
	} );

	describe( 'getSourceData', () => {
		it( 'returns empty object if the post is not a discover post', () => {
			assert.deepEqual( {}, helper.getSourceData( fixtures.nonDiscoverPost ) );
		} );

		it( 'returns empty object if the post is external', () => {
			assert.deepEqual( {}, helper.getSourceData( fixtures.externalDiscoverPost ) );
		} );

		it( 'returns blog id if the post is a discover site pick', () => {
			const fixtureData = {
				blogId: get(
					fixtures.discoverSiteFormat,
					'discover_metadata.featured_post_wpcom_data.blog_id'
				),
				postId: undefined,
			};
			assert.deepEqual( fixtureData, helper.getSourceData( fixtures.discoverSiteFormat ) );
		} );

		it( 'returns the post and blog id', () => {
			const fixtureData = {
				blogId: get( discoverPost, 'discover_metadata.featured_post_wpcom_data.blog_id' ),
				postId: get( discoverPost, 'discover_metadata.featured_post_wpcom_data.post_id' ),
			};
			assert.deepEqual( fixtureData, helper.getSourceData( discoverPost ) );
		} );
	} );

	describe( 'getLinkProps', () => {
		it( 'returns empty props if the post is internal', () => {
			const siteUrl = helper.getSiteUrl( discoverPost );
			assert.deepEqual( helper.getLinkProps( siteUrl ), { rel: '', target: '' } );
		} );

		it( 'returns props for external posts', () => {
			const siteUrl = helper.getSiteUrl( fixtures.externalDiscoverPost );
			assert.deepEqual( helper.getLinkProps( siteUrl ), { rel: 'external', target: '_blank' } );
		} );
	} );

	describe( 'getSourceFollowUrl', () => {
		it( 'returns the site url if its a discover pick to an internal site', () => {
			const followUrl = helper.getSourceFollowUrl( discoverPost );
			assert.equal( followUrl, get( discoverPost, 'discover_metadata.attribution.blog_url' ) );
		} );

		it( 'returns undefined if the post is not a discover pick', () => {
			const followUrl = helper.getSourceFollowUrl( fixtures.nonDiscoverPost );
			assert.isUndefined( followUrl );
		} );
	} );
} );
示例#27
0
describe( 'MediaActions', function() {
	let mediaGet, mediaList, mediaAdd, mediaAddUrls, mediaUpdate, mediaDelete,
		MediaActions, sandbox, Dispatcher, PostEditStore, MediaListStore;

	useFakeDom();
	useMockery();

	before( function() {
		Dispatcher = require( 'dispatcher' );
		PostEditStore = require( 'lib/posts/post-edit-store' );
		MediaListStore = require( '../list-store' );

		mockery.registerMock( './library-selected-store', {
			getAll: function() {
				return [ DUMMY_ITEM ];
			}
		} );
		mockery.registerMock( './store', {
			get: function() {
				return DUMMY_ITEM;
			}
		} );
		mockery.registerMock( 'lib/wp', {
			site: function( siteId ) {
				return {
					addMediaFiles: mediaAdd.bind( siteId ),
					addMediaUrls: mediaAddUrls.bind( siteId ),
					mediaList: mediaList.bind( siteId ),
					media: function( mediaId ) {
						return {
							get: mediaGet.bind( [ siteId, mediaId ].join() ),
							update: mediaUpdate.bind( [ siteId, mediaId ].join() ),
							'delete': mediaDelete.bind( [ siteId, mediaId ].join() )
						};
					}
				};
			}
		} );
		mockery.registerMock( 'lodash/uniqueId', function() {
			return 'media-1';
		} );
		mockery.registerMock( 'lodash/isPlainObject', function( obj ) {
			// In the browser, our DUMMY_UPLOAD will be an instanceof
			// window.File, but File is not provided by jsdom
			if ( obj === DUMMY_UPLOAD ) {
				return false;
			}

			return isPlainObject( obj );
		} );

		MediaActions = require( '../actions' );
	} );

	beforeEach( function() {
		sandbox = sinon.sandbox.create();
		sandbox.stub( Dispatcher, 'handleServerAction' );
		sandbox.stub( Dispatcher, 'handleViewAction' );
		mediaGet = sandbox.stub().callsArgWithAsync( 0, null, DUMMY_API_RESPONSE );
		mediaList = sandbox.stub().callsArgWithAsync( 1, null, DUMMY_API_RESPONSE );
		mediaAdd = sandbox.stub().returns( Promise.resolve( DUMMY_API_RESPONSE ) );
		mediaAddUrls = sandbox.stub().returns( Promise.resolve( DUMMY_API_RESPONSE ) );
		mediaUpdate = sandbox.stub().callsArgWithAsync( 1, null, DUMMY_API_RESPONSE );
		mediaDelete = sandbox.stub().callsArgWithAsync( 0, null, DUMMY_API_RESPONSE );
		MediaActions._fetching = {};
		window.FileList = function() {};
		window.URL = { createObjectURL: sandbox.stub() };
	} );

	afterEach( function() {
		sandbox.restore();
		delete window.FileList;
		delete window.URL;
	} );

	after( function() {
		mockery.deregisterAll();
		mockery.disable();
	} );

	describe( '#setQuery()', function() {
		it( 'should dispatch the SET_MEDIA_QUERY action', function() {
			MediaActions.setQuery( DUMMY_SITE_ID, DUMMY_QUERY );

			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'SET_MEDIA_QUERY',
				siteId: DUMMY_SITE_ID,
				query: DUMMY_QUERY
			} );
		} );
	} );

	describe( '#fetch()', function() {
		it( 'should call to the WordPress.com REST API', function( done ) {
			Dispatcher.handleViewAction.restore();
			sandbox.stub( Dispatcher, 'handleViewAction', function() {
				expect( MediaActions._fetching ).to.have.all.keys( [ [ DUMMY_SITE_ID, DUMMY_ITEM.ID ].join() ] );
			} );

			MediaActions.fetch( DUMMY_SITE_ID, DUMMY_ITEM.ID );

			expect( Dispatcher.handleViewAction ).to.have.been.calledOnce;
			expect( mediaGet ).to.have.been.calledOn( [ DUMMY_SITE_ID, DUMMY_ITEM.ID ].join() );
			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_MEDIA_ITEM',
					error: null,
					siteId: DUMMY_SITE_ID,
					data: DUMMY_API_RESPONSE
				} );

				done();
			} );
		} );

		it( 'should not allow simultaneous request for the same item', function() {
			MediaActions.fetch( DUMMY_SITE_ID, DUMMY_ITEM.ID );
			MediaActions.fetch( DUMMY_SITE_ID, DUMMY_ITEM.ID );

			expect( mediaGet ).to.have.been.calledOnce;
		} );

		it( 'should allow simultaneous request for different items', function() {
			MediaActions.fetch( DUMMY_SITE_ID, DUMMY_ITEM.ID );
			MediaActions.fetch( DUMMY_SITE_ID, DUMMY_ITEM.ID + 1 );

			expect( mediaGet ).to.have.been.calledTwice;
		} );
	} );

	describe( '#fetchNextPage()', function() {
		it( 'should call to the WordPress.com REST API', function( done ) {
			var query = MediaListStore.getNextPageQuery( DUMMY_SITE_ID );

			MediaActions.fetchNextPage( DUMMY_SITE_ID );

			expect( mediaList ).to.have.been.calledOn( DUMMY_SITE_ID );
			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_MEDIA_ITEMS',
					error: null,
					siteId: DUMMY_SITE_ID,
					data: DUMMY_API_RESPONSE,
					query: query
				} );

				done();
			} );
		} );
	} );

	describe( '#add()', function() {
		it( 'should accept a single upload', function() {
			MediaActions.add( DUMMY_SITE_ID, DUMMY_UPLOAD );
			expect( Dispatcher.handleViewAction ).to.have.been.calledOnce;
			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'CREATE_MEDIA_ITEM'
			} );
		} );

		it( 'should accept an array of uploads', function() {
			MediaActions.add( DUMMY_SITE_ID, [ DUMMY_UPLOAD, DUMMY_UPLOAD ] );
			expect( Dispatcher.handleViewAction ).to.have.been.calledTwice;
			expect( Dispatcher.handleViewAction ).to.have.always.been.calledWithMatch( {
				type: 'CREATE_MEDIA_ITEM'
			} );
		} );

		it( 'should accept a file URL', function() {
			return MediaActions.add( DUMMY_SITE_ID, DUMMY_URL ).then( () => {
				expect( mediaAddUrls ).to.have.been.calledWithMatch( {}, DUMMY_URL );
			} );
		} );

		it( 'should accept a FileList of uploads', function() {
			var uploads = [ DUMMY_UPLOAD, DUMMY_UPLOAD ];
			uploads.__proto__ = new window.FileList(); // eslint-disable-line no-proto
			MediaActions.add( DUMMY_SITE_ID, uploads );
			expect( Dispatcher.handleViewAction ).to.have.been.calledTwice;
			expect( Dispatcher.handleViewAction ).to.have.always.been.calledWithMatch( {
				type: 'CREATE_MEDIA_ITEM'
			} );
		} );

		it( 'should accept a Blob object wrapper and pass it as "file" parameter', function() {
			return MediaActions.add( DUMMY_SITE_ID, DUMMY_BLOB_UPLOAD ).then( () => {
				expect( mediaAdd ).to.have.been.calledWithMatch( {}, { file: DUMMY_BLOB_UPLOAD } );
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_MEDIA_ITEM',
					siteId: DUMMY_SITE_ID,
					id: 'media-1',
					data: DUMMY_API_RESPONSE.media[ 0 ]
				} );
			} );
		} );

		it( 'should call to the WordPress.com REST API', function() {
			return MediaActions.add( DUMMY_SITE_ID, DUMMY_UPLOAD ).then( () => {
				expect( mediaAdd ).to.have.been.calledWithMatch( {}, DUMMY_UPLOAD );
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_MEDIA_ITEM',
					siteId: DUMMY_SITE_ID,
					id: 'media-1',
					data: DUMMY_API_RESPONSE.media[ 0 ]
				} );
			} );
		} );

		it( 'should immediately receive a transient object', function() {
			MediaActions.add( DUMMY_SITE_ID, DUMMY_UPLOAD );

			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'CREATE_MEDIA_ITEM',
				data: {
					ID: 'media-1',
					file: DUMMY_UPLOAD.name,
					'transient': true
				}
			} );
		} );

		it( 'should attach file upload to a post if one is being edited', function() {
			sandbox.stub( PostEditStore, 'get' ).returns( { ID: 200 } );

			return MediaActions.add( DUMMY_SITE_ID, DUMMY_UPLOAD ).then( () => {
				expect( mediaAdd ).to.have.been.calledWithMatch( {}, {
					file: DUMMY_UPLOAD,
					parent_id: 200
				} );
			} );
		} );

		it( 'should attach URL upload to a post if one is being edited', function() {
			sandbox.stub( PostEditStore, 'get' ).returns( { ID: 200 } );

			return MediaActions.add( DUMMY_SITE_ID, DUMMY_URL ).then( () => {
				expect( mediaAddUrls ).to.have.been.calledWithMatch( {}, {
					url: DUMMY_URL,
					parent_id: 200
				} );
			} );
		} );

		it( 'should upload in series', () => {
			// An awkward test, but the idea is that at the point at which
			// handleServerAction is called for the first received media,
			// only the first of the two items should have started uploading.
			Dispatcher.handleServerAction.restore();
			sandbox.stub( Dispatcher, 'handleServerAction' ).throws();

			return MediaActions.add( DUMMY_SITE_ID, [ DUMMY_UPLOAD, DUMMY_UPLOAD ] ).then( () => {
				expect( Dispatcher.handleServerAction ).to.have.thrown;
			} ).catch( () => {
				expect( mediaAdd ).to.have.been.calledOnce;
			} );
		} );
	} );

	describe( '#edit()', function() {
		var item = { ID: 100, description: 'Example' };

		it( 'should immediately edit the existing item', function() {
			MediaActions.edit( DUMMY_SITE_ID, item );

			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'RECEIVE_MEDIA_ITEM',
				siteId: DUMMY_SITE_ID,
				data: assign( {}, DUMMY_ITEM, item )
			} );
		} );
	} );

	describe( '#update()', function() {
		var item = { ID: 100, description: 'Example' };

		it( 'should accept a single item', function() {
			MediaActions.update( DUMMY_SITE_ID, item );
			expect( mediaUpdate ).to.have.been.calledOnce;
		} );

		it( 'should accept an array of items', function() {
			MediaActions.update( DUMMY_SITE_ID, [ item, item ] );
			expect( mediaUpdate ).to.have.been.calledTwice;
		} );

		it( 'should immediately update the existing item', function() {
			MediaActions.update( DUMMY_SITE_ID, item );

			expect( mediaUpdate ).to.have.been.calledWithMatch( item );
			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'RECEIVE_MEDIA_ITEM',
				siteId: DUMMY_SITE_ID,
				data: assign( {}, DUMMY_ITEM, item )
			} );
		} );

		it( 'should call to the WordPress.com REST API', function( done ) {
			MediaActions.update( DUMMY_SITE_ID, item );

			expect( mediaUpdate ).to.have.been.calledWithMatch( item );

			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'RECEIVE_MEDIA_ITEM',
					error: null,
					siteId: DUMMY_SITE_ID,
					data: DUMMY_API_RESPONSE
				} );

				done();
			} );
		} );
	} );

	describe( '#delete()', function() {
		var item = { ID: 100 };

		it( 'should accept a single item', function() {
			MediaActions.delete( DUMMY_SITE_ID, item );
			expect( mediaDelete ).to.have.been.calledOnce;
		} );

		it( 'should accept an array of items', function() {
			MediaActions.delete( DUMMY_SITE_ID, [ item, item ] );
			expect( mediaDelete ).to.have.been.calledTwice;
		} );

		it( 'should call to the WordPress.com REST API', function( done ) {
			MediaActions.delete( DUMMY_SITE_ID, item );

			expect( mediaDelete ).to.have.been.calledOn( [ DUMMY_SITE_ID, item.ID ].join() );
			process.nextTick( function() {
				expect( Dispatcher.handleServerAction ).to.have.been.calledWithMatch( {
					type: 'REMOVE_MEDIA_ITEM',
					error: null,
					siteId: DUMMY_SITE_ID,
					data: DUMMY_API_RESPONSE
				} );

				done();
			} );
		} );

		it( 'should immediately remove the item', function() {
			MediaActions.delete( DUMMY_SITE_ID, item );

			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'REMOVE_MEDIA_ITEM',
				siteId: DUMMY_SITE_ID,
				data: item
			} );
		} );
	} );

	describe( '#clearValidationErrors()', function() {
		it( 'should dispatch the `CLEAR_MEDIA_VALIDATION_ERRORS` action with the specified siteId', function() {
			MediaActions.clearValidationErrors( DUMMY_SITE_ID );

			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'CLEAR_MEDIA_VALIDATION_ERRORS',
				siteId: DUMMY_SITE_ID,
				itemId: undefined
			} );
		} );

		it( 'should dispatch the `CLEAR_MEDIA_VALIDATION_ERRORS` action with the specified siteId and itemId', function() {
			MediaActions.clearValidationErrors( DUMMY_SITE_ID, DUMMY_ITEM.ID );

			expect( Dispatcher.handleViewAction ).to.have.been.calledWithMatch( {
				type: 'CLEAR_MEDIA_VALIDATION_ERRORS',
				siteId: DUMMY_SITE_ID,
				itemId: DUMMY_ITEM.ID
			} );
		} );
	} );
} );
示例#28
0
describe( 'markup', function() {
	let sandbox, markup, sites;

	useFakeDom();
	useSandbox( ( newSandbox ) => sandbox = newSandbox );
	useMockery( mockery => {
		mockery.registerMock( 'lib/wp', {
			me: () => ( {
				get: noop
			} )
		} );
	} );

	before( () => {
		markup = require( '../markup' );
		sites = require( 'lib/sites-list' )();
	} );

	beforeEach( () => {
		sandbox.restore();
	} );

	describe( '#get()', function() {
		it( 'should return an empty string if not passed any arguments', function() {
			var value = markup.get();

			expect( value ).to.equal( '' );
		} );

		it( 'should defer to a specific mime type handler if one exists', function() {
			sandbox.stub( markup.mimeTypes, 'image' );
			markup.get( { mime_type: 'image/png' } );

			expect( markup.mimeTypes.image ).to.have.been.called;
		} );

		it( 'should return a link for a mime type prefix without a specific handler', function() {
			sandbox.stub( markup, 'link' );
			markup.get( { mime_type: 'application/pdf' } );

			expect( markup.link ).to.have.been.called;
		} );
	} );

	describe( '#link()', function() {
		it( 'should return a link for a mime type prefix without a specific handler', function() {
			var value = markup.link( {
				URL: 'http://example.com/wp-content/uploads/document.pdf',
				title: 'document'
			} );

			expect( value ).to.equal( '<a href="http://example.com/wp-content/uploads/document.pdf" title="document">document</a>' );
		} );
	} );

	describe( '#caption()', function() {
		it( 'should accept a media object, returning a caption element', function() {
			var value = markup.caption( {
				ID: 1,
				URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
				alt: 'Automattic',
				caption: 'Logo',
				thumbnails: {},
				width: 276
			} );

			expect( value.type ).to.equal( 'dl' );
			expect( ReactDomServer.renderToStaticMarkup( value ) ).to.equal( '<dl class="wp-caption" style="width:276px;"><dt class="wp-caption-dt"><img src="https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png" alt="Automattic" width="276" class="alignnone size-full wp-image-1"/></dt><dd class="wp-caption-dd">Logo</dd></dl>' );
		} );

		it( 'should accept a non-captioned image, returning null', function() {
			var value = markup.caption( {
				ID: 1,
				URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
				alt: 'Automattic',
				thumbnails: {},
				width: 276
			} );

			expect( value ).to.be.null;
		} );

		it( 'should accept a captioned string, returning a React element', function() {
			var value = markup.caption( '[caption id="attachment_1627" align="aligncenter" width="660"]<img class="size-full wp-image-1627" src="https://andrewmduthietest.files.wordpress.com/2015/01/img_0372.jpg" alt="Example" width="660" height="660" /> Ceramic[/caption]' );

			expect( value.type ).to.equal( 'dl' );
			expect( ReactDomServer.renderToStaticMarkup( value ) ).to.equal( '<dl class="wp-caption aligncenter" style="width:660px;"><dt class="wp-caption-dt"><img class="size-full wp-image-1627" src="https://andrewmduthietest.files.wordpress.com/2015/01/img_0372.jpg" alt="Example" width="660" height="660" /></dt><dd class="wp-caption-dd">Ceramic</dd></dl>' );
		} );
	} );

	describe( '.mimeTypes', function() {
		describe( '#image()', function() {
			beforeEach( function() {
				sandbox.stub( sites, 'getSelectedSite', function() {
					return {};
				} );
			} );

			it( 'should not set width auto if media width cannot be determined', function() {
				var value = markup.mimeTypes.image( {
					ID: 'media-4',
					URL: 'blob:http%3A//example.com/ddd1d6b0-f31b-4937-ae9e-97f1d660cf71',
					thumbnails: {}
				} );

				expect( value ).to.equal( '<img src="blob:http%3A//example.com/ddd1d6b0-f31b-4937-ae9e-97f1d660cf71" class="alignnone size-full wp-image-media-4"/>' );
			} );

			it( 'should return an img element for an image', function() {
				var value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
					alt: 'Automattic',
					thumbnails: {},
					width: 276
				} );

				expect( value ).to.equal( '<img src="https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png" alt="Automattic" width="276" class="alignnone size-full wp-image-1"/>' );
			} );

			it( 'should respect the max width for a site size', function() {
				sites.getSelectedSite.restore();
				sandbox.stub( sites, 'getSelectedSite', function() {
					return {
						options: {
							image_large_width: 1024,
							image_large_height: 1024
						}
					};
				} );

				const value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'http://example.com/image.png',
					thumbnails: {},
					width: 5000,
					height: 2000
				}, { size: 'large' } );

				sites.getSelectedSite.restore();

				expect( value ).to.equal( '<img src="http://example.com/image.png?w=1024" width="1024" height="410" class="alignnone size-large wp-image-1"/>' );
			} );

			it( 'should respect the max height for a site size', function() {
				sites.getSelectedSite.restore();
				sandbox.stub( sites, 'getSelectedSite', function() {
					return {
						options: {
							image_large_width: 1024,
							image_large_height: 1024
						}
					};
				} );

				const value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'http://example.com/image.png',
					thumbnails: {},
					width: 2000,
					height: 5000
				}, { size: 'large' } );

				sites.getSelectedSite.restore();

				expect( value ).to.equal( '<img src="http://example.com/image.png?w=410" width="410" height="1024" class="alignnone size-large wp-image-1"/>' );
			} );

			it( 'should include a resize parameter if forceResize option passed', function() {
				var value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
					alt: 'Automattic',
					thumbnails: {},
					width: 276
				}, { forceResize: true } );

				expect( value ).to.equal( '<img src="https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png?w=276" alt="Automattic" width="276" class="alignnone size-full wp-image-1"/>' );
			} );

			it( 'should avoid XSS because React', function() {
				var value = markup.mimeTypes.image( {
					ID: 1,
					URL: '""><SCRIPT>alert("XSS")</SCRIPT>"',
					thumbnails: {},
					width: 276
				} );

				expect( value ).to.equal( '<img src="&quot;&quot;&gt;&lt;SCRIPT&gt;alert(&quot;XSS&quot;)&lt;/SCRIPT&gt;&quot;" width="276" class="alignnone size-full wp-image-1"/>' );
			} );

			it( 'should attempt to find the site\'s thumbnail width if a size is specified', function() {
				var value;

				sites.getSelectedSite.restore();
				sandbox.stub( sites, 'getSelectedSite', function() {
					return {
						options: {
							image_large_width: 200
						}
					};
				} );

				value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
					alt: 'Automattic',
					thumbnails: {},
					width: 276
				}, { size: 'large' } );

				sites.getSelectedSite.restore();

				expect( value ).to.equal( '<img src="https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png?w=200" alt="Automattic" width="200" class="alignnone size-large wp-image-1"/>' );
			} );

			it( 'should attempt to find the media\'s own thumbnail width if a size is specified', function() {
				var value;

				sites.getSelectedSite.restore();
				sandbox.stub( sites, 'getSelectedSite', function() {
					return { jetpack: true };
				} );

				value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'http://example.com/wp-content/uploads/2015/05/logo11w.png',
					alt: 'WordPress',
					thumbnails: {
						large: 'http://example.com/wp-content/uploads/2015/05/logo11w-1024x1024.png'
					},
					width: 5380
				}, { size: 'large' } );

				sites.getSelectedSite.restore();

				expect( value ).to.equal( '<img src="http://example.com/wp-content/uploads/2015/05/logo11w-1024x1024.png" alt="WordPress" width="1024" class="alignnone size-large wp-image-1"/>' );
			} );

			it( 'should wrap a captioned image in a caption shortcode', function() {
				var value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
					alt: 'Automattic',
					caption: 'Logo',
					thumbnails: {},
					width: 276
				} );

				expect( value ).to.equal( '[caption id="attachment_1" width="276"]<img src="https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png" alt="Automattic" width="276" class="alignnone size-full wp-image-1"/> Logo[/caption]' );
			} );

			it( 'should calculate the height when specifying a size', function() {
				var value = markup.mimeTypes.image( {
					ID: 1,
					URL: 'https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png',
					alt: 'Automattic',
					thumbnails: {},
					width: 2760,
					height: 300
				}, { size: 'large' } );

				expect( value ).to.equal( '<img src="https://s1.wp.com/wp-content/themes/a8c/automattic-2011/images/automattic-logo.png?w=1024" alt="Automattic" width="1024" height="111" class="alignnone size-large wp-image-1"/>' );
			} );
		} );

		describe( '#audio()', function() {
			it( 'should return an `audio` shortcode for an audio item', function() {
				var value = markup.mimeTypes.audio( {
					URL: 'http://example.com/wp-content/uploads/2015/06/loop.mp3'
				} );

				expect( value ).to.equal( '[audio src="http://example.com/wp-content/uploads/2015/06/loop.mp3"][/audio]' );
			} );
		} );

		describe( '#video()', function() {
			it( 'should return a `wpvideo` shortcode for a VideoPress video', function() {
				var value = markup.mimeTypes.video( {
					videopress_guid: '11acMj3O'
				} );

				expect( value ).to.equal( '[wpvideo 11acMj3O]' );
			} );

			it( 'should return a `video` shortcode for a video', function() {
				var value = markup.mimeTypes.video( {
					URL: 'http://example.com/wp-content/uploads/2015/06/loop.mp4',
					height: 454,
					width: 1436
				} );

				expect( value ).to.equal( '[video src="http://example.com/wp-content/uploads/2015/06/loop.mp4" height="454" width="1436"][/video]' );
			} );
		} );
	} );
} );
示例#29
0
describe( 'devdocs', () => {
	let app, server;

	allowNetworkAccess();
	useMockery();

	before( done => {
		mockery.registerMock( 'config', {
			isEnabled: () => true
		} );
		// for speed - the real search index is very large
		mockery.registerMock( 'devdocs/search-index', {
			index: {}
		} );
		mockery.registerMock( 'lunr', {
			Index: {
				load: () => null
			}
		} );

		devdocs = require( '../' );
		app = devdocs();
		server = app.listen( 9993, done );
	} );

	after( done => {
		server.close( done );
	} );

	it( 'should return documents', done => {
		getDocument(
			'README.md',
			( err, res ) => {
				expect( err ).to.be.null;
				expect( res.statusCode ).to.equal( 200 );
				expect( res.text ).to.contain( '<a href="./.github/CONTRIBUTING.md">' );
				done();
			} );
	} );

	it( 'should return documents with relative paths', done => {
		getDocument(
			'client/components/infinite-list',
			'../../lib/mixins/infinite-scroll/README.md',
			( err, res ) => {
				expect( err ).to.be.null;
				expect( res.statusCode ).to.equal( 200 );
				expect( res.text ).to.contain( '<h1 id="infinite-scroll">' );
				done();
			} );
	} );

	it( 'should return the README.md by default', done => {
		getDocument(
			'client/lib/mixins/infinite-scroll',
			( err, res ) => {
				expect( err ).to.be.null;
				expect( res.statusCode ).to.equal( 200 );
				expect( res.text ).to.contain( '<h1 id="infinite-scroll">' );
				done();
			} );
	} );

	it( 'should not allow viewing files outside the Calypso repo', done => {
		const pathOutsideCalypso = fspath.join( __dirname, '..', '..', '..', '..', 'outside-calypso.md' );
		fs.writeFileSync( pathOutsideCalypso, 'oh no' );
		getDocument(
			'../outside-calypso.md',
			( err, res ) => {
				fs.unlinkSync( pathOutsideCalypso );
				expect( err ).not.to.be.null;
				expect( res.statusCode ).to.equal( 404 );
				expect( res.text ).to.equal( 'File does not exist' );
				done();
			} );
	} );

	it( 'should not allow viewing JavaScript files', done => {
		getDocument(
			'index.js',
			( err, res ) => {
				expect( err ).not.to.be.null;
				expect( res.statusCode ).to.equal( 404 );
				expect( res.text ).to.equal( 'File does not exist' );
				done();
			} );
	} );
} );
示例#30
0
describe( 'index', function() {
	useFakeDom();

	useFilesystemMocks( __dirname );

	useMockery( mockery => {
		mockery.registerSubstitute( 'matches-selector', 'component-matches-selector' );
	} );

	let SitesDropdown;

	before( function() {
		SitesDropdown = require( '..' ).SitesDropdown;
	} );

	describe( 'component rendering', function() {
		it( 'should render a dropdown component initially closed', function() {
			const sitesDropdown = shallow( <SitesDropdown /> );
			expect( sitesDropdown.hasClass( 'sites-dropdown' ) ).to.be.true;
			expect( sitesDropdown.hasClass( 'is-open' ) ).to.be.false;
		} );

		it( 'should toggle the dropdown, when it is clicked', function() {
			const toggleOpenSpy = sinon.spy( SitesDropdown.prototype, 'toggleOpen' );
			const sitesDropdown = shallow( <SitesDropdown /> );

			sitesDropdown.find( '.sites-dropdown__selected' ).simulate( 'click' );

			sinon.assert.calledOnce( toggleOpenSpy );
			expect( sitesDropdown.hasClass( 'is-open' ) ).to.be.true;

			toggleOpenSpy.restore();
		} );
	} );

	describe( 'component state', function() {
		it( 'should initially consider as selected the selectedOrPrimarySiteId prop', function() {
			const sitesDropdown = shallow( <SitesDropdown selectedSiteId={ 1234567 } /> );
			expect( sitesDropdown.instance().state.selectedSiteId ).to.be.equal( 1234567 );
		} );
	} );

	describe( 'selectSite', function() {
		it( 'should update the `selectedSiteSlug`, and `open` state properties', function() {
			const setStateSpy = sinon.spy();
			const siteSelectedSpy = sinon.spy();
			const fakeContext = {
				setState: setStateSpy,
				props: {
					onSiteSelect: siteSelectedSpy,
				}
			};

			SitesDropdown.prototype.selectSite.call( fakeContext, 12345 );

			sinon.assert.calledOnce( siteSelectedSpy );
			sinon.assert.calledWith( siteSelectedSpy, 12345 );

			sinon.assert.calledOnce( setStateSpy );
			sinon.assert.calledWith( setStateSpy, { open: false, selectedSiteId: 12345 } );
		} );
	} );

	describe( 'onClose', function() {
		it( 'should set `open` state property to false', function() {
			const setStateSpy = sinon.spy();
			const fakeContext = {
				setState: setStateSpy,
				props: {
					onClose: noop
				}
			};

			SitesDropdown.prototype.onClose.call( fakeContext );

			sinon.assert.calledOnce( setStateSpy );
			sinon.assert.calledWith( setStateSpy, { open: false } );
		} );

		it( 'should run the component `onClose` hook, when it is provided', function() {
			const onCloseSpy = sinon.spy();
			const fakeContext = {
				setState: noop,
				props: {
					onClose: onCloseSpy
				}
			};

			SitesDropdown.prototype.onClose.call( fakeContext );
			sinon.assert.calledOnce( onCloseSpy );
		} );
	} );

	describe( 'getSelectedSite', function() {
		xit( 'should return a site on the basis of the component `selectedSiteSlug` state property', function() {
			const fakeState = {
				selectedSiteId: 42
			};
			const selectedSite = SitesDropdown.prototype.getSelectedSite.call( { state: fakeState } );
			expect( selectedSite ).to.be.eql( {
				ID: 42,
				slug: 'foo.wordpress.com'
			} );
		} );
	} );
} );