Skip to content

Commit

Permalink
Add unit tests for sharing data store (#34206)
Browse files Browse the repository at this point in the history
* Enhance RecordBarMeter component with `className`

* Add changelog

* Add store types

* Update store selectors and actions

* Update consumer hook to use new selectors

* Create useShareLimits hook

* Move `ShareCounter` to publicize-components and name it `ShareLimitsBar`

* Create separate notice components

* Fix the post editor notices

* Update Jetpack Social admin page to use the new meter bar

* Remove unused code left after #34111

* Add changelog

* Fix share count

* Update index.js

* Include active connections count for notices

* Fix i18n build error

* Enhance RecordBarMeter component with `className`

* Add changelog

* Extract constants and improve types

* Add types/jest

* Add tests for sharesData selectors

* Add tests for useShareLimits hook

* rename to *.test.js

* extract utility

* Create add-tests-for-sharing-data

* Update shares-data.test.js

* Extract messages to utility function

* Use the messages from utility function

* Enhance RecordBarMeter component with `className`

* Add changelog

* Fix up versions

* Revert "Remove unused code left after #34111"

This reverts commit ca45999.

* Use @wordpress/element instead of react

* Fix messaging

* Let TS infer type

* Combine the share limits logic into a single useSelect call

* Fix the limits shown even after a paid plan

* Enhance RecordBarMeter component with `className`

* Add changelog

* Enhance RecordBarMeter component with `className`

* Add changelog

* Jetpack Social | Warn the user that their scheduled posts won't get shared if they will get over limits. (#34183)

* Enhance RecordBarMeter component with `className`

* Add changelog

* Add store types

* Update store selectors and actions

* Update consumer hook to use new selectors

* Create useShareLimits hook

* Move `ShareCounter` to publicize-components and name it `ShareLimitsBar`

* Create separate notice components

* Fix the post editor notices

* Update Jetpack Social admin page to use the new meter bar

* Remove unused code left after #34111

* Add changelog

* Fix share count

* Update index.js

* Include active connections count for notices

* Fix i18n build error

* Enhance RecordBarMeter component with `className`

* Add changelog

* Extract constants and improve types

* Extract messages to utility function

* Enhance RecordBarMeter component with `className`

* Add changelog

* Fix up versions

* Revert "Remove unused code left after #34111"

This reverts commit ca45999.

* Use @wordpress/element instead of react

* Fix messaging

* Let TS infer type

* Combine the share limits logic into a single useSelect call

* Fix the limits shown even after a paid plan

* Update tests
  • Loading branch information
manzoorwanijk committed Nov 28, 2023
1 parent 6442532 commit 2b7db1d
Show file tree
Hide file tree
Showing 7 changed files with 630 additions and 0 deletions.
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added


1 change: 1 addition & 0 deletions projects/js-packages/publicize-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@testing-library/dom": "8.19.1",
"@testing-library/react": "13.4.0",
"@testing-library/user-event": "14.4.3",
"@types/jest": "29.2.5",
"@types/react": "18.2.33",
"@wordpress/babel-plugin-import-jsx-pragma": "4.28.0",
"@wordpress/core-data": "6.22.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import { renderHook } from '@testing-library/react';
import { RegistryProvider, createRegistry, createReduxStore } from '@wordpress/data';
import { WPDataRegistry } from '@wordpress/data/build-types/registry';
import { getMessages, useShareLimits } from '../';
import { SOCIAL_STORE_CONFIG, SOCIAL_STORE_ID } from '../../../social-store';
import { SocialStoreState } from '../../../social-store/types';
import { createActiveConnections } from '../../../utils/test-utils';

type DeepPartial< T > = T extends object
? {
[ P in keyof T ]?: DeepPartial< T[ P ] >;
}
: T;

/**
* Create a registry with stores.
*
* @param {Partial< SocialStoreState >} initialState - Initial state for the store.
*
* @returns {WPDataRegistry} Registry.
*/
function createRegistryWithStores( initialState = {} ) {
// Create a registry.
const registry = createRegistry();

const socialStore = createReduxStore( SOCIAL_STORE_ID, { ...SOCIAL_STORE_CONFIG, initialState } );
// Register stores.
// @ts-expect-error The registry type is not correct. This comment can be removed when register() exists in the type.
registry.register( socialStore );

return registry;
}

/**
* Returns the initial state for the store.
*
* @param {Partial< SocialStoreState >} data - Data to override the default state
*
* @returns {SocialStoreState} Initial state for the store
*/
function getStoreInitialState( data: DeepPartial< SocialStoreState > ) {
return {
...data,
sharesData: {
is_share_limit_enabled: true,
to_be_publicized_count: 0,
share_limit: 30,
publicized_count: 0,
show_advanced_plan_upgrade_nudge: false,
shared_posts_count: 0,
...data.sharesData,
},
};
}

const messages = getMessages( 30 );

describe( 'useShareLimits', () => {
it( 'should return the default values', () => {
const { result } = renderHook( () => useShareLimits() );

expect( result.current ).toEqual( {
status: 'none',
noticeType: 'default',
message: messages.default,
} );
} );

const testCases = [
{
name: 'should return the default values at the beginning',
sharesData: {
publicized_count: 0,
to_be_publicized_count: 0,
},
expected: {
status: 'none',
noticeType: 'default',
message: messages.default,
},
},
{
name: 'should return "none" with default messages when used + scheduled < limit',
sharesData: {
publicized_count: 5,
to_be_publicized_count: 5,
},
expected: {
status: 'none',
noticeType: 'default',
message: messages.default,
},
},
{
name: 'should return "full" with limit exceeded message when the limit is reached without scheduled posts',
sharesData: {
publicized_count: 30,
to_be_publicized_count: 0,
},
expected: {
status: 'full',
noticeType: 'error',
message: messages.exceeded,
},
},
{
name: 'should return "full" with scheduled shares message when the limit is reached with scheduled posts',
sharesData: {
publicized_count: 15,
to_be_publicized_count: 15,
},
expected: {
status: 'full',
noticeType: 'warning',
message: messages.scheduled,
},
},
{
name: 'should return "crossed" with limit exceeded message when the limit is crossed without scheduled posts',
sharesData: {
publicized_count: 35, // impossible to reach this number but just in case
to_be_publicized_count: 0,
},
expected: {
status: 'exceeded',
noticeType: 'error',
message: messages.exceeded,
},
},
{
name: 'should return "crossed" with limit exceeded message when the limit is crossed with scheduled posts',
sharesData: {
publicized_count: 30,
to_be_publicized_count: 5,
},
expected: {
status: 'exceeded',
noticeType: 'error',
message: messages.exceeded,
},
},
{
name: 'should return "approaching" with approaching limit message when the limit is approached without scheduled posts',
sharesData: {
publicized_count: 25,
to_be_publicized_count: 0,
},
expected: {
status: 'approaching',
noticeType: 'warning',
message: messages.approaching,
},
},
{
name: 'should return "approaching" with approaching limit message when the limit is approached with scheduled posts',
sharesData: {
publicized_count: 20,
to_be_publicized_count: 5,
},
expected: {
status: 'approaching',
noticeType: 'warning',
message: messages.approaching,
},
},
{
name: 'should return "none" when everything including active connections is well below the limit',
sharesData: {
publicized_count: 5,
to_be_publicized_count: 5,
},
connectionData: {
connections: createActiveConnections( 5 ),
},
expected: {
status: 'none',
noticeType: 'default',
message: messages.default,
},
},
{
name: 'should return "approaching" when approaching the limit with active connections',
sharesData: {
publicized_count: 10,
to_be_publicized_count: 10,
},
connectionData: {
connections: createActiveConnections( 5 ),
},
expected: {
status: 'approaching',
noticeType: 'warning',
message: messages.approaching,
},
},
{
name: 'should return "full" with a warning when the limit is reached with active connections',
sharesData: {
publicized_count: 15,
to_be_publicized_count: 10,
},
connectionData: {
connections: createActiveConnections( 5 ),
},
expected: {
status: 'full',
noticeType: 'warning',
message: messages.scheduled,
},
},
{
name: 'should return "crossed" with a warning when the limit is crossed with active connections',
sharesData: {
publicized_count: 20,
to_be_publicized_count: 10,
},
connectionData: {
connections: createActiveConnections( 5 ),
},
expected: {
status: 'exceeded',
noticeType: 'warning',
message: messages.scheduled,
},
},
];

for ( const { name, expected, ...initiaState } of testCases ) {
describe( 'dynamic tests', () => {
it( `${ name }`, () => {
const { result } = renderHook( () => useShareLimits(), {
wrapper: ( { children } ) => (
<RegistryProvider
value={ createRegistryWithStores( getStoreInitialState( initiaState ) ) }
>
{ children }
</RegistryProvider>
),
} );

expect( result.current ).toEqual( expected );
} );
} );
}
} );
Loading

0 comments on commit 2b7db1d

Please sign in to comment.