Add tests for UI Revamp on Marketing page (#34840)

This commit is contained in:
Gan Eng Chin 2022-09-27 22:25:48 +08:00 committed by GitHub
parent c31f8b0aa5
commit 9e697cdf0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 283 additions and 21 deletions

View File

@ -0,0 +1,41 @@
/**
* External dependencies
*/
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
/**
* Internal dependencies
*/
import { CollapsibleCard } from './CollapsibleCard';
const header = 'Card header';
const body = 'Card body';
describe( 'CollapsibleCard component', () => {
it( 'should render a card that can be expanded or collapsed when the card header is clicked', async () => {
render( <CollapsibleCard header={ header }>{ body }</CollapsibleCard> );
// Card is expanded by default.
expect( screen.queryByText( header ) ).toBeInTheDocument();
expect( screen.queryByText( body ) ).toBeInTheDocument();
// Click on card header to collapsed the card.
await userEvent.click( screen.getByText( header ) );
// Card body should not be there.
expect( screen.queryByText( body ) ).not.toBeInTheDocument();
} );
it( 'should render a card that is collapsed by default when `initialCollapsed` is set', async () => {
render(
<CollapsibleCard initialCollapsed header={ header }>
{ body }
</CollapsibleCard>
);
// Card is collapsed by default.
expect( screen.queryByText( header ) ).toBeInTheDocument();
expect( screen.queryByText( body ) ).not.toBeInTheDocument();
} );
} );

View File

@ -0,0 +1,146 @@
/**
* External dependencies
*/
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
/**
* Internal dependencies
*/
import { useBlogPosts } from './useBlogPosts';
import { LearnMarketing } from './LearnMarketing';
jest.mock( './useBlogPosts', () => ( {
useBlogPosts: jest.fn(),
} ) );
describe( 'LearnMarketing component', () => {
it( 'should render placeholders when loading is in progress', async () => {
( useBlogPosts as jest.Mock ).mockReturnValue( {
isLoading: true,
error: undefined,
posts: [],
} );
render( <LearnMarketing /> );
// Click on expand button to expand the card.
await userEvent.click(
screen.getByRole( 'button', { name: 'Expand' } )
);
// should render three elements with the "progressbar" role:
// two from the PlaceholderPostTile, and one in the card footer.
expect( screen.getAllByRole( 'progressbar' ) ).toHaveLength( 3 );
} );
it( 'should render an error message when there is an error', async () => {
( useBlogPosts as jest.Mock ).mockReturnValue( {
isLoading: false,
error: new Error(),
posts: [],
} );
render( <LearnMarketing /> );
// Click on expand button to expand the card.
await userEvent.click(
screen.getByRole( 'button', { name: 'Expand' } )
);
expect(
screen.getByText( "Oops, our posts aren't loading right now" )
).toBeInTheDocument();
} );
it( 'should render "No posts yet" when loading is done and there are no posts', async () => {
( useBlogPosts as jest.Mock ).mockReturnValue( {
isLoading: false,
error: undefined,
posts: [],
} );
render( <LearnMarketing /> );
// Click on expand button to expand the card.
await userEvent.click(
screen.getByRole( 'button', { name: 'Expand' } )
);
expect( screen.getByText( 'No posts yet' ) ).toBeInTheDocument();
} );
it( 'should render two posts in one page with pagination when loading is done and there are posts', async () => {
( useBlogPosts as jest.Mock ).mockReturnValue( {
isLoading: false,
error: undefined,
posts: [
{
title: 'Grow Your Store with an Omnichannel Presence',
date: '2022-09-21T19:46:40',
link: 'https://woocommerce.com/posts/grow-store-omnichannel-ecommerce/',
author_name: 'Kathryn Marr',
author_avatar:
'https://secure.gravatar.com/avatar/431b87d722d366103cc5d9b26c66c665?s=96&d=mm&r=g',
image: 'https://woocommerce.com/wp-content/uploads/2022/09/blog-fb-Omnichannel@2x.jpg?resize=650,340&crop=1',
},
{
title: 'What is Affiliate Marketing and How to Use it to Make More Money Online',
date: '2022-08-30T22:03:54',
link: 'https://woocommerce.com/posts/what-is-affliate-marketing/',
author_name: 'Kathryn Marr',
author_avatar:
'https://secure.gravatar.com/avatar/431b87d722d366103cc5d9b26c66c665?s=96&d=mm&r=g',
image: 'https://woocommerce.com/wp-content/uploads/2022/08/blog-fb-Affiliate@2x.jpg?resize=650,340&crop=1',
},
{
title: 'Ten Customer Retention Strategies to Boost Revenue for eCommerce Stores',
date: '2022-06-22T17:58:12',
link: 'https://woocommerce.com/posts/10-ecommerce-customer-retention-strategies-boost-revenue/',
author_name: 'Craig Cohen',
author_avatar:
'https://secure.gravatar.com/avatar/66c306ae543fb47f594ef9b9cdb88d93?s=96&d=mm&r=g',
},
{
title: 'TikTok Marketing: A Guide for WooCommerce Stores',
date: '2022-05-25T14:03:00',
link: 'https://woocommerce.com/posts/tiktok-marketing-a-guide-for-woocommerce-stores/',
author_name: 'Elina Vilk',
author_avatar:
'https://secure.gravatar.com/avatar/fc7aedb0e531795eeffa3654ce203a8e?s=96&d=mm&r=g',
image: 'https://woocommerce.com/wp-content/uploads/2022/05/Facebook-Post-1200x630@2x3.jpg?resize=650,340&crop=1',
},
],
} );
render( <LearnMarketing /> );
// Click on expand button to expand the card.
await userEvent.click(
screen.getByRole( 'button', { name: 'Expand' } )
);
// Assert that the first and second post title are in the page.
expect(
screen.getByText( 'Grow Your Store with an Omnichannel Presence' )
).toBeInTheDocument();
expect(
screen.getByText(
'What is Affiliate Marketing and How to Use it to Make More Money Online'
)
).toBeInTheDocument();
// Click on the next page button in card footer.
await userEvent.click(
screen.getByRole( 'button', { name: 'Next Page' } )
);
// Assert that the third and fourth post title are in the page.
expect(
screen.getByText(
'Ten Customer Retention Strategies to Boost Revenue for eCommerce Stores'
)
).toBeInTheDocument();
expect(
screen.getByText(
'TikTok Marketing: A Guide for WooCommerce Stores'
)
).toBeInTheDocument();
} );
} );

View File

@ -3,17 +3,15 @@
*/ */
import { useState } from '@wordpress/element'; import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { Pagination, EmptyContent } from '@woocommerce/components'; import { Pagination, EmptyContent } from '@woocommerce/components';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { CollapsibleCard, ReadBlogMessage } from '~/marketing/components'; import { CollapsibleCard, ReadBlogMessage } from '~/marketing/components';
import { STORE_KEY } from '~/marketing/data/constants';
import { PlaceholderPostTile } from './PlaceholderPostTile'; import { PlaceholderPostTile } from './PlaceholderPostTile';
import { PostTile } from './PostTile'; import { PostTile } from './PostTile';
import { Post } from './types'; import { useBlogPosts } from './useBlogPosts';
import './LearnMarketing.scss'; import './LearnMarketing.scss';
const BLOG_POST_CATEGORY = 'marketing'; const BLOG_POST_CATEGORY = 'marketing';
@ -21,21 +19,7 @@ const PER_PAGE = 2;
export const LearnMarketing = () => { export const LearnMarketing = () => {
const [ page, setPage ] = useState( 1 ); const [ page, setPage ] = useState( 1 );
const { isLoading, error, posts } = useSelect( const { isLoading, error, posts } = useBlogPosts( BLOG_POST_CATEGORY );
( select ) => {
const { getBlogPosts, getBlogPostsError, isResolving } =
select( STORE_KEY );
return {
posts: getBlogPosts( BLOG_POST_CATEGORY ),
isLoading: isResolving( 'getBlogPosts', [
BLOG_POST_CATEGORY,
] ),
error: getBlogPostsError( BLOG_POST_CATEGORY ),
};
},
[ BLOG_POST_CATEGORY ]
);
/** /**
* Renders card footer. * Renders card footer.
@ -47,7 +31,10 @@ export const LearnMarketing = () => {
const renderFooter = () => { const renderFooter = () => {
if ( isLoading ) { if ( isLoading ) {
return ( return (
<div className="woocommerce-marketing-learn-marketing-card__footer--placeholder" /> <div
role="progressbar"
className="woocommerce-marketing-learn-marketing-card__footer--placeholder"
/>
); );
} }
@ -111,7 +98,7 @@ export const LearnMarketing = () => {
return posts return posts
.slice( ( page - 1 ) * PER_PAGE, page * PER_PAGE ) .slice( ( page - 1 ) * PER_PAGE, page * PER_PAGE )
.map( ( post: Post, index: number ) => { .map( ( post, index ) => {
return <PostTile key={ index } post={ post } />; return <PostTile key={ index } post={ post } />;
} ); } );
}; };

View File

@ -1,6 +1,9 @@
export const PlaceholderPostTile = () => { export const PlaceholderPostTile = () => {
return ( return (
<div className="woocommerce-marketing-learn-marketing-card__post"> <div
role="progressbar"
className="woocommerce-marketing-learn-marketing-card__post"
>
<div className="woocommerce-marketing-learn-marketing-card__post-img woocommerce-marketing-learn-marketing-card__post-img--placeholder" /> <div className="woocommerce-marketing-learn-marketing-card__post-img woocommerce-marketing-learn-marketing-card__post-img--placeholder" />
<div className="woocommerce-marketing-learn-marketing-card__post-title woocommerce-marketing-learn-marketing-card__post-title--placeholder" /> <div className="woocommerce-marketing-learn-marketing-card__post-title woocommerce-marketing-learn-marketing-card__post-title--placeholder" />
<div className="woocommerce-marketing-learn-marketing-card__post-description woocommerce-marketing-learn-marketing-card__post-description--placeholder" /> <div className="woocommerce-marketing-learn-marketing-card__post-description woocommerce-marketing-learn-marketing-card__post-description--placeholder" />

View File

@ -0,0 +1,26 @@
/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { STORE_KEY } from '~/marketing/data/constants';
import { Post } from './types';
export const useBlogPosts = ( category: string ) => {
return useSelect(
( select ) => {
const { getBlogPosts, getBlogPostsError, isResolving } =
select( STORE_KEY );
return {
isLoading: isResolving( 'getBlogPosts', [ category ] ),
error: getBlogPostsError( category ),
posts: getBlogPosts< Post[] >( category ),
};
},
[ category ]
);
};

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Add tests for UI Revamp on Marketing Page.

View File

@ -0,0 +1,55 @@
const { test, expect } = require( '@playwright/test' );
test.describe( 'Marketing page', () => {
test.use( { storageState: process.env.ADMINSTATE } );
test( 'A user can disable the Multichannel Marketing feature in WC Settings and view the Marketing > Overview page without it crashing', async ( {
page,
} ) => {
// Go to WC Settings > Advanced > Features page.
await page.goto(
'wp-admin/admin.php?page=wc-settings&tab=advanced&section=features'
);
// Disable multichannel marketing experience by unchecking the checkbox and clicking on "Save changes" button.
await page
.locator(
'"Enables the new WooCommerce Multichannel Marketing experience in the Marketing page"'
)
.uncheck();
await page.locator( '"Save changes"' ).click();
// Go to the Marketing page.
await page.goto( 'wp-admin/admin.php?page=wc-admin&path=%2Fmarketing' );
// Users should see the knowledge base card.
await expect(
page.locator( '"WooCommerce knowledge base"' )
).toBeVisible();
} );
test( 'A user can enable the Multichannel Marketing feature in WC Settings and view the Marketing > Overview page without it crashing', async ( {
page,
} ) => {
// Go to WC Settings > Advanced > Features page.
await page.goto(
'wp-admin/admin.php?page=wc-settings&tab=advanced&section=features'
);
// Enable multichannel marketing experience by checking the checkbox and clicking on "Save changes" button.
await page
.locator(
'"Enables the new WooCommerce Multichannel Marketing experience in the Marketing page"'
)
.check();
await page.locator( '"Save changes"' ).click();
// Go to the Marketing page.
await page.goto( 'wp-admin/admin.php?page=wc-admin&path=%2Fmarketing' );
// Users should see the "Learn about marketing a store" card.
await expect(
page.locator( '"Learn about marketing a store"' )
).toBeVisible();
} );
} );