Add unit tests for some tracks in product editor (#48245)

* Add tests for ProductPage

* Add tests for ProductVariationPage

* Add test for product_tab_click event

* Add test for product_editor_feedback_bar_turnoff_editor_click event

* Add test for product_dropdown_option_click event

* Add test for product_add_view track

* Changelogs

* Changelog

* Lint

* Add product_edit_view test and falsey test

* Fix test name
This commit is contained in:
Ilyas Foo 2024-06-10 23:05:20 +08:00 committed by GitHub
parent 1167b54a3d
commit 0d461fa6e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 353 additions and 0 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Add tests for some product editor tracks

View File

@ -51,6 +51,9 @@ module.exports = {
'**/test/*.[jt]s?(x)',
'**/?(*.)test.[jt]s?(x)',
],
testPathIgnorePatterns: [
'\\.d\\.ts$', // This regex pattern matches any file that ends with .d.ts
],
// The keys for the transformed modules contains the name of the packages that should be transformed.
transformIgnorePatterns: [
'node_modules/(?!(?:\\.pnpm|' + Object.keys( transformModules ).join( '|' ) + ')/)',

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Add tests for some product editor tracks

View File

@ -0,0 +1,44 @@
/**
* External dependencies
*/
import { act, fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { createElement } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
/**
* Internal dependencies
*/
import { FeedbackBar } from '../feedback-bar';
import { useFeedbackBar } from '../../../hooks/use-feedback-bar';
jest.mock( '../../../hooks/use-feedback-bar', () => ( {
...jest.requireActual( '../../../hooks/use-feedback-bar' ),
useFeedbackBar: jest.fn(),
} ) );
jest.mock( '@woocommerce/tracks', () => ( {
...jest.requireActual( '@woocommerce/tracks' ),
recordEvent: jest.fn(),
} ) );
describe( 'FeedbackBar', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_editor_feedback_bar_turnoff_editor_click event when clicking turn off editor', () => {
( useFeedbackBar as jest.Mock ).mockImplementation( () => ( {
hideFeedbackBar: () => {},
shouldShowFeedbackBar: true,
} ) );
render( <FeedbackBar productType={ 'testing' } /> );
act( () => {
fireEvent.click( screen.getByText( 'turn it off' ) );
} );
expect( recordEvent ).toBeCalledWith(
'product_editor_feedback_bar_turnoff_editor_click',
{ product_type: 'testing' }
);
} );
} );

View File

@ -6,6 +6,8 @@ import { render, fireEvent, screen } from '@testing-library/react';
import { getQuery, navigateTo } from '@woocommerce/navigation';
import { SlotFillProvider } from '@wordpress/components';
import { useState, createElement } from '@wordpress/element';
import { recordEvent } from '@woocommerce/tracks';
import { select } from '@wordpress/data';
/**
* Internal dependencies
@ -15,6 +17,7 @@ import {
TabBlockEdit as Tab,
TabBlockAttributes,
} from '../../../blocks/generic/tab/edit';
import { TRACKS_SOURCE } from '../../../constants';
jest.mock( '@woocommerce/block-templates', () => ( {
...jest.requireActual( '@woocommerce/block-templates' ),
@ -27,6 +30,19 @@ jest.mock( '@woocommerce/navigation', () => ( {
getQuery: jest.fn().mockReturnValue( {} ),
} ) );
jest.mock( '@woocommerce/tracks', () => ( {
...jest.requireActual( '@woocommerce/tracks' ),
recordEvent: jest.fn(),
} ) );
jest.mock( '@wordpress/data', () => {
const originalModule = jest.requireActual( '@wordpress/data' );
return {
...originalModule,
select: jest.fn( ( ...args ) => originalModule.select( ...args ) ),
};
} );
const blockProps = {
setAttributes: () => {},
className: '',
@ -109,6 +125,7 @@ function MockTabs( { onChange = jest.fn() } ) {
describe( 'Tabs', () => {
beforeEach( () => {
jest.clearAllMocks();
( getQuery as jest.Mock ).mockReturnValue( {
tab: null,
} );
@ -224,4 +241,21 @@ describe( 'Tabs', () => {
expect( panel1.classList ).not.toContain( 'is-selected' );
expect( panel2.classList ).toContain( 'is-selected' );
} );
it( 'should trigger wcadmin_product_tab_click track event when tab is clicked', async () => {
( select as jest.Mock ).mockImplementation( () => ( {
getEditedEntityRecord: () => ( {
type: 'simple',
} ),
} ) );
render( <MockTabs /> );
const button = screen.getByText( 'Test button 2' );
fireEvent.click( button );
expect( recordEvent ).toBeCalledWith( 'product_tab_click', {
product_tab: 'test2',
product_type: 'simple',
source: TRACKS_SOURCE,
} );
} );
} );

View File

@ -0,0 +1,58 @@
/**
* External dependencies
*/
import { render, fireEvent } from '@testing-library/react';
import { useSelect, useDispatch } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks';
import { useParams } from 'react-router-dom';
/**
* Internal dependencies
*/
import { DeleteVariationMenuItem } from '../delete-variation-menu-item';
jest.mock( '@wordpress/data', () => ( {
...jest.requireActual( '@wordpress/data' ),
useDispatch: jest.fn(),
useSelect: jest.fn(),
} ) );
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
jest.mock( 'react-router-dom', () => ( { useParams: jest.fn() } ) );
jest.mock( '@wordpress/core-data', () => ( {
useEntityId: jest.fn().mockReturnValue( 'variation_1' ),
useEntityProp: jest
.fn()
.mockImplementation( ( _1, _2, propType ) => [ propType ] ),
} ) );
describe( 'DeleteVariationMenuItem', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_dropdown_option_click track event when clicking the menu', async () => {
( useDispatch as jest.Mock ).mockReturnValue( {
deleteProductVariation: () => {},
} );
( useSelect as jest.Mock ).mockReturnValue( {
type: 'simple',
status: 'publish',
} );
( useParams as jest.Mock ).mockReturnValue( { productId: 1 } );
const { getByText } = render(
<DeleteVariationMenuItem onClose={ () => {} } />
);
fireEvent.click( getByText( 'Delete variation' ) );
expect( recordEvent ).toHaveBeenCalledWith(
'product_dropdown_option_click',
{
product_id: 1,
product_status: 'status',
selected_option: 'delete_variation',
variation_id: 'variation_1',
}
);
} );
} );

View File

@ -0,0 +1,49 @@
/**
* External dependencies
*/
import { render, fireEvent } from '@testing-library/react';
import { useSelect } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks';
/**
* Internal dependencies
*/
import { MoreMenuFill } from '../product-block-editor-fills';
jest.mock( '@wordpress/data', () => ( {
...jest.requireActual( '@wordpress/data' ),
useSelect: jest.fn(),
} ) );
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
jest.mock( '../more-menu-items', () => ( {
...jest.requireActual( '../more-menu-items' ),
ClassicEditorMenuItem: jest.fn().mockImplementation( () => <div></div> ),
FeedbackMenuItem: jest.fn().mockImplementation( ( { onClick } ) => (
<div>
<button onClick={ onClick }>Feedback button</button>
</div>
) ),
} ) );
describe( 'MoreMenuFill', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_dropdown_option_click track event when clicking the menu', async () => {
( useSelect as jest.Mock ).mockReturnValue( {
type: 'simple',
status: 'publish',
} );
const { getByText } = render( <MoreMenuFill onClose={ () => {} } /> );
fireEvent.click( getByText( 'Feedback button' ) );
expect( recordEvent ).toHaveBeenCalledWith(
'product_dropdown_option_click',
{
product_status: 'publish',
product_type: 'simple',
selected_option: 'feedback',
}
);
} );
} );

View File

@ -0,0 +1,80 @@
/**
* External dependencies
*/
import { render } from '@testing-library/react';
import { recordEvent } from '@woocommerce/tracks';
import { TRACKS_SOURCE } from '@woocommerce/product-editor';
import { useParams } from 'react-router-dom';
/**
* Internal dependencies
*/
import ProductPage from '../product-page';
import ProductVariationPage from '../product-variation-page';
jest.mock( '@woocommerce/tracks', () => ( {
recordEvent: jest.fn(),
} ) );
jest.mock( 'react-router-dom', () => ( { useParams: jest.fn() } ) );
// Mocks to prevent crashes.
jest.mock( '@wordpress/api-fetch', () => ( {
apiFetch: jest.fn(),
} ) );
jest.mock( '@wordpress/core-data', () => ( {
apiFetch: jest.fn(),
} ) );
jest.mock( '../hooks/use-product-entity-record', () => ( {
useProductEntityRecord: jest.fn(),
} ) );
jest.mock( '../hooks/use-product-variation-entity-record', () => ( {
useProductVariationEntityRecord: jest.fn(),
} ) );
jest.mock( '@woocommerce/product-editor', () => ( {
...jest.requireActual( '@woocommerce/product-editor' ),
productEditorHeaderApiFetchMiddleware: jest.fn(),
productApiFetchMiddleware: jest.fn(),
__experimentalInitBlocks: jest.fn().mockImplementation( () => () => {} ),
} ) );
describe( 'ProductPage', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_add_view on render without product_id defined', () => {
( useParams as jest.Mock ).mockReturnValue( { productId: null } );
render( <ProductPage /> );
expect( recordEvent ).toBeCalledWith( 'product_add_view', {
source: TRACKS_SOURCE,
} );
} );
it( 'should trigger product_edit_view on render with product_id defined', () => {
( useParams as jest.Mock ).mockReturnValue( { productId: 1 } );
render( <ProductPage /> );
expect( recordEvent ).toBeCalledWith( 'product_edit_view', {
source: TRACKS_SOURCE,
product_id: 1,
} );
} );
} );
describe( 'ProductVariationPage', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_add_view track event on render without product_id defined', () => {
( useParams as jest.Mock ).mockReturnValue( { productId: null } );
render( <ProductVariationPage /> );
expect( recordEvent ).toBeCalledWith( 'product_add_view', {
source: TRACKS_SOURCE,
} );
} );
it( 'should trigger product_edit_view track event on render with product_id defined', () => {
( useParams as jest.Mock ).mockReturnValue( { productId: 1 } );
render( <ProductVariationPage /> );
expect( recordEvent ).toBeCalledWith( 'product_edit_view', {
source: TRACKS_SOURCE,
product_id: 1,
} );
} );
} );

View File

@ -0,0 +1,4 @@
declare const productScreen: { name: string };
declare const global: typeof globalThis & {
productScreen: typeof productScreen;
};

View File

@ -0,0 +1,36 @@
/**
* @jest-environment node
*/
/**
* External dependencies
*/
import { recordEvent } from '@woocommerce/tracks';
jest.mock( '@woocommerce/tracks', () => ( {
recordEvent: jest.fn(),
} ) );
jest.mock( '../shared', () => ( {
addExitPageListener: jest.fn().mockImplementation( () => {} ),
initProductScreenTracks: jest.fn().mockImplementation( () => {} ),
getProductData: jest.fn().mockImplementation( () => ( { product_id: 1 } ) ),
} ) );
describe( 'Product Screen Tracking', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_edit_view event when productScreen.name is "edit"', () => {
global.productScreen = { name: 'edit' };
require( '../product-edit' );
expect( recordEvent ).toHaveBeenCalledWith( 'product_edit_view', {
product_id: 1,
} );
} );
it( 'should not trigger product_edit_view event when productScreen.name is not "edit"', () => {
global.productScreen = { name: '' };
require( '../product-edit' );
expect( recordEvent ).not.toHaveBeenCalled();
} );
} );

View File

@ -0,0 +1,33 @@
/**
* @jest-environment node
*/
/**
* External dependencies
*/
import { recordEvent } from '@woocommerce/tracks';
jest.mock( '@woocommerce/tracks', () => ( {
recordEvent: jest.fn(),
} ) );
jest.mock( '../shared', () => ( {
addExitPageListener: jest.fn().mockImplementation( () => {} ),
initProductScreenTracks: jest.fn().mockImplementation( () => {} ),
} ) );
describe( 'Product Screen Tracking', () => {
beforeEach( () => {
jest.clearAllMocks();
} );
it( 'should trigger product_add_view event when productScreen.name is "new"', () => {
global.productScreen = { name: 'new' };
require( '../product-new' );
expect( recordEvent ).toHaveBeenCalledWith( 'product_add_view' );
} );
it( 'should not trigger product_add_view event when productScreen.name is not "new"', () => {
global.productScreen = { name: '' };
require( '../product-new' );
expect( recordEvent ).not.toHaveBeenCalled();
} );
} );

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Add tests for some product editor tracks