Product Block Editor: use `<AttributesComboboxControl />` in the Attributes modal (#47093)
* update combobox story * first step replacing with attribute combobox * introduce takenBy prop * filter attributes when taken * add and tweak combobox styles * changelog * tweak wrapped item * update tests * pass instanceNumber * remove commented line
This commit is contained in:
parent
b107cff519
commit
5ab1241ac2
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: update
|
||||
|
||||
Product Block Editor: replace custom select with the combobox control core component in the product attributes
|
|
@ -2,7 +2,6 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import {
|
||||
BaseControl,
|
||||
ComboboxControl as CoreComboboxControl,
|
||||
|
@ -15,18 +14,11 @@ import {
|
|||
useRef,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import {
|
||||
EXPERIMENTAL_PRODUCT_ATTRIBUTES_STORE_NAME,
|
||||
type ProductAttributesActions,
|
||||
WPDataActions,
|
||||
} from '@woocommerce/data';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { TRACKS_SOURCE } from '../../constants';
|
||||
import type {
|
||||
AttributesComboboxControlItem,
|
||||
AttributesComboboxControlComponent,
|
||||
|
@ -101,22 +93,13 @@ const AttributesComboboxControl: React.FC<
|
|||
help,
|
||||
current = null,
|
||||
items = [],
|
||||
createNewAttributesAsGlobal = false,
|
||||
instanceNumber = 0,
|
||||
isLoading = false,
|
||||
onChange,
|
||||
} ) => {
|
||||
const createErrorNotice = useDispatch( 'core/notices' )?.createErrorNotice;
|
||||
const { createProductAttribute } = useDispatch(
|
||||
EXPERIMENTAL_PRODUCT_ATTRIBUTES_STORE_NAME
|
||||
) as unknown as ProductAttributesActions & WPDataActions;
|
||||
|
||||
const [ createNewAttributeOption, updateCreateNewAttributeOption ] =
|
||||
useState< ComboboxControlOption >( createNewAttributeOptionDefault );
|
||||
|
||||
const clearCreateNewAttributeItem = () =>
|
||||
updateCreateNewAttributeOption( createNewAttributeOptionDefault );
|
||||
|
||||
/**
|
||||
* Map the items to the Combobox options.
|
||||
* Each option is an object with a label and value.
|
||||
|
@ -155,48 +138,6 @@ const AttributesComboboxControl: React.FC<
|
|||
currentValue = 'create-attribute';
|
||||
}
|
||||
|
||||
const addNewAttribute = ( name: string ) => {
|
||||
recordEvent( 'product_attribute_add_custom_attribute', {
|
||||
source: TRACKS_SOURCE,
|
||||
} );
|
||||
if ( createNewAttributesAsGlobal ) {
|
||||
createProductAttribute(
|
||||
{
|
||||
name,
|
||||
generate_slug: true,
|
||||
},
|
||||
{
|
||||
optimisticQueryUpdate: {
|
||||
order_by: 'name',
|
||||
},
|
||||
}
|
||||
).then(
|
||||
( newAttr ) => {
|
||||
onChange( newAttr );
|
||||
clearCreateNewAttributeItem();
|
||||
setAttributeSelected( true );
|
||||
},
|
||||
( error ) => {
|
||||
let message = __(
|
||||
'Failed to create new attribute.',
|
||||
'woocommerce'
|
||||
);
|
||||
if ( error.code === 'woocommerce_rest_cannot_create' ) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
createErrorNotice?.( message, {
|
||||
explicitDismiss: true,
|
||||
} );
|
||||
|
||||
clearCreateNewAttributeItem();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
onChange( items.find( ( i ) => i.name === name ) );
|
||||
}
|
||||
};
|
||||
|
||||
const comboRef = useRef< HTMLDivElement | null >( null );
|
||||
|
||||
// Label to link the input with the label.
|
||||
|
@ -292,8 +233,11 @@ const AttributesComboboxControl: React.FC<
|
|||
...createNewAttributeOption,
|
||||
state: 'creating',
|
||||
} );
|
||||
addNewAttribute( createNewAttributeOption.label );
|
||||
return;
|
||||
|
||||
return onChange( {
|
||||
id: -99,
|
||||
name: createNewAttributeOption.label,
|
||||
} );
|
||||
}
|
||||
|
||||
setAttributeSelected( true );
|
||||
|
|
|
@ -3,99 +3,91 @@
|
|||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import React, { useState } from 'react';
|
||||
import type { ProductAttribute } from '@woocommerce/data';
|
||||
import '@wordpress/interface/src/style.scss';
|
||||
import { ProductAttribute } from '@woocommerce/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import AttributesComboboxControl from '../';
|
||||
import type { AttributesComboboxControlComponent } from '../types';
|
||||
import type {
|
||||
AttributesComboboxControlComponent,
|
||||
AttributesComboboxControlItem,
|
||||
} from '../types';
|
||||
|
||||
export default {
|
||||
title: 'Product Editor/components/AttributesComboboxControl',
|
||||
component: AttributesComboboxControl,
|
||||
};
|
||||
|
||||
const items = [
|
||||
const items: AttributesComboboxControlItem[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Color',
|
||||
slug: 'pa_color',
|
||||
takenBy: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Size',
|
||||
slug: 'pa_size',
|
||||
takenBy: 1,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Material',
|
||||
slug: 'pa_material',
|
||||
takenBy: 1,
|
||||
isDisabled: true,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Style',
|
||||
slug: 'pa_style',
|
||||
takenBy: 1,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Brand',
|
||||
slug: 'pa_brand',
|
||||
takenBy: 1,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Pattern',
|
||||
slug: 'pa_pattern',
|
||||
takenBy: 1,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Theme',
|
||||
slug: 'pa_theme',
|
||||
takenBy: 1,
|
||||
isDisabled: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Collection',
|
||||
slug: 'pa_collection',
|
||||
takenBy: 1,
|
||||
isDisabled: true,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Occasion',
|
||||
slug: 'pa_occasion',
|
||||
takenBy: 1,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: 'Season',
|
||||
slug: 'pa_season',
|
||||
takenBy: 1,
|
||||
},
|
||||
];
|
||||
|
||||
export const Default = ( args: AttributesComboboxControlComponent ) => {
|
||||
const [ selectedAttribute, setSelectedAttribute ] = useState<
|
||||
ProductAttribute | undefined
|
||||
>();
|
||||
const [ selectedAttribute, setSelectedAttribute ] =
|
||||
useState< AttributesComboboxControlItem | null >( null );
|
||||
|
||||
function selectAttribute( item: ProductAttribute | string | undefined ) {
|
||||
function selectAttribute( item: AttributesComboboxControlItem ) {
|
||||
if ( typeof item === 'string' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSelectedAttribute( item );
|
||||
args.onChange( item );
|
||||
}
|
||||
|
||||
return (
|
||||
<AttributesComboboxControl
|
||||
{ ...args }
|
||||
label={ __( 'Attributes', 'woocommerce' ) }
|
||||
items={ items }
|
||||
help={ __(
|
||||
'Select or create attributes for this product.',
|
||||
'woocommerce'
|
||||
) }
|
||||
onChange={ selectAttribute }
|
||||
current={ selectedAttribute }
|
||||
/>
|
||||
|
@ -103,11 +95,31 @@ export const Default = ( args: AttributesComboboxControlComponent ) => {
|
|||
};
|
||||
|
||||
Default.args = {
|
||||
label: __( 'Attributes', 'woocommerce' ),
|
||||
items,
|
||||
help: __( 'Select or create attributes for this product.', 'woocommerce' ),
|
||||
|
||||
onChange: ( newValue: ProductAttribute ) => {
|
||||
console.log( '(onChange) newValue:', newValue ); // eslint-disable-line no-console
|
||||
},
|
||||
};
|
||||
|
||||
export const MultipleInstances = (
|
||||
args: AttributesComboboxControlComponent
|
||||
) => {
|
||||
return (
|
||||
<>
|
||||
<AttributesComboboxControl
|
||||
{ ...args }
|
||||
label={ __( 'Attributes 1', 'woocommerce' ) }
|
||||
items={ items }
|
||||
instanceNumber={ 1 }
|
||||
/>
|
||||
|
||||
<AttributesComboboxControl
|
||||
{ ...args }
|
||||
label={ __( 'Attributes 2', 'woocommerce' ) }
|
||||
items={ items }
|
||||
instanceNumber={ 2 }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
MultipleInstances.args = Default.args;
|
||||
|
|
|
@ -12,16 +12,10 @@
|
|||
background-color: white;
|
||||
|
||||
> .components-flex {
|
||||
height: 32px;
|
||||
height: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.components-combobox-control__suggestions-container {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
max-height: 128px;
|
||||
}
|
||||
|
||||
.components-form-token-field__suggestion {
|
||||
padding: 0;
|
||||
min-height: 32px;
|
||||
|
@ -29,7 +23,10 @@
|
|||
align-items: center;
|
||||
|
||||
.item-wrapper {
|
||||
padding: 8px 12px;
|
||||
padding: 0 12px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
width: 100%;
|
||||
|
||||
&.is-disabled {
|
||||
background-color: #fafafa;
|
||||
|
|
|
@ -8,8 +8,12 @@ import type { ProductAttribute } from '@woocommerce/data';
|
|||
* which is a combination of the product attribute and
|
||||
* additional properties.
|
||||
*/
|
||||
export type AttributesComboboxControlItem = ProductAttribute & {
|
||||
export type AttributesComboboxControlItem = Pick<
|
||||
ProductAttribute,
|
||||
'id' | 'name'
|
||||
> & {
|
||||
isDisabled?: boolean;
|
||||
takenBy?: number;
|
||||
};
|
||||
|
||||
export type AttributesComboboxControlComponent = {
|
||||
|
@ -20,13 +24,13 @@ export type AttributesComboboxControlComponent = {
|
|||
disabled?: boolean;
|
||||
instanceNumber?: number;
|
||||
|
||||
current?: AttributesComboboxControlItem;
|
||||
current: AttributesComboboxControlItem | null;
|
||||
items: AttributesComboboxControlItem[];
|
||||
|
||||
disabledAttributeMessage?: string;
|
||||
createNewAttributesAsGlobal?: boolean;
|
||||
|
||||
onChange: ( value?: AttributesComboboxControlItem ) => void;
|
||||
onChange: ( value: AttributesComboboxControlItem ) => void;
|
||||
};
|
||||
|
||||
export type ComboboxControlOption = {
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
&__body {
|
||||
min-height: 200px;
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&__table {
|
||||
|
@ -82,7 +81,7 @@
|
|||
&__table-attribute-trash-column {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-items:flex-start;
|
||||
|
||||
@include breakpoint( '<782px' ) {
|
||||
position: absolute;
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
type ProductAttributesActions,
|
||||
type WPDataActions,
|
||||
type ProductAttributeTerm,
|
||||
type ProductAttribute,
|
||||
} from '@woocommerce/data';
|
||||
import { Button, Modal, Notice } from '@wordpress/components';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
|
@ -22,7 +23,6 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { AttributeInputField } from '../attribute-input-field';
|
||||
import {
|
||||
AttributeTermInputField,
|
||||
CustomAttributeTermInputField,
|
||||
|
@ -30,6 +30,8 @@ import {
|
|||
import { TRACKS_SOURCE } from '../../constants';
|
||||
import type { AttributeInputFieldItemProps } from '../attribute-input-field/types';
|
||||
import type { EnhancedProductAttribute } from '../../hooks/use-product-attributes';
|
||||
import AttributesComboboxControl from '../attribute-combobox-field';
|
||||
import { AttributesComboboxControlItem } from '../attribute-combobox-field/types';
|
||||
|
||||
type NewAttributeModalProps = {
|
||||
title?: string;
|
||||
|
@ -308,7 +310,7 @@ export const NewAttributeModal: React.FC< NewAttributeModalProps > = ( {
|
|||
}
|
||||
|
||||
function selectAttributeHandler(
|
||||
nextAttribute: AttributeInputFieldItemProps,
|
||||
nextAttribute: AttributesComboboxControlItem,
|
||||
index: number
|
||||
) {
|
||||
recordEvent( 'product_attribute_add_custom_attribute', {
|
||||
|
@ -378,33 +380,30 @@ export const NewAttributeModal: React.FC< NewAttributeModalProps > = ( {
|
|||
}
|
||||
|
||||
/*
|
||||
* Get the attribute ids that should be ignored when filtering the attributes
|
||||
* to show in the attribute input field.
|
||||
* Get the attribute ids that are already selected
|
||||
* by other form fields.
|
||||
*/
|
||||
const ignoredAttributeIds = [
|
||||
...selectedAttributeIds,
|
||||
...values.attributes
|
||||
.map( ( attr ) => attr?.id )
|
||||
.filter(
|
||||
( attrId ): attrId is number =>
|
||||
attrId !== undefined
|
||||
),
|
||||
];
|
||||
const attributeBelongTo = values.attributes.map( ( attr ) =>
|
||||
attr ? attr.id : null
|
||||
);
|
||||
|
||||
/*
|
||||
* Compute the available attributes to show in the attribute input field,
|
||||
* filtering out the ignored attributes and marking the disabled ones.
|
||||
* filtering out the ignored attributes,
|
||||
* marking the disabled ones,
|
||||
* and setting the takenBy property.
|
||||
*/
|
||||
const availableAttributes = attributes
|
||||
?.filter(
|
||||
( attribute: EnhancedProductAttribute ) =>
|
||||
! ignoredAttributeIds.includes( attribute.id )
|
||||
( attribute: ProductAttribute ) =>
|
||||
! selectedAttributeIds.includes( attribute.id )
|
||||
)
|
||||
.map( ( attribute: EnhancedProductAttribute ) => ( {
|
||||
?.map( ( attribute: ProductAttribute ) => ( {
|
||||
...attribute,
|
||||
isDisabled: disabledAttributeIds.includes(
|
||||
attribute.id
|
||||
),
|
||||
takenBy: attributeBelongTo.indexOf( attribute.id ),
|
||||
} ) );
|
||||
|
||||
return (
|
||||
|
@ -446,20 +445,29 @@ export const NewAttributeModal: React.FC< NewAttributeModalProps > = ( {
|
|||
className={ `woocommerce-new-attribute-modal__table-row woocommerce-new-attribute-modal__table-row-${ index }` }
|
||||
>
|
||||
<td className="woocommerce-new-attribute-modal__table-attribute-column">
|
||||
<AttributeInputField
|
||||
<AttributesComboboxControl
|
||||
placeholder={
|
||||
attributePlaceholder
|
||||
}
|
||||
value={ attribute }
|
||||
items={
|
||||
availableAttributes
|
||||
current={
|
||||
attribute
|
||||
}
|
||||
instanceNumber={
|
||||
index
|
||||
}
|
||||
items={ availableAttributes?.filter(
|
||||
(
|
||||
attr: AttributesComboboxControlItem
|
||||
) =>
|
||||
( attr.takenBy &&
|
||||
attr.takenBy <
|
||||
0 ) ||
|
||||
attr.takenBy ===
|
||||
index
|
||||
) }
|
||||
isLoading={
|
||||
isLoading
|
||||
}
|
||||
label={
|
||||
attributeLabel
|
||||
}
|
||||
onChange={ (
|
||||
nextAttribute
|
||||
) =>
|
||||
|
@ -468,9 +476,6 @@ export const NewAttributeModal: React.FC< NewAttributeModalProps > = ( {
|
|||
index
|
||||
)
|
||||
}
|
||||
disabledAttributeIds={
|
||||
disabledAttributeIds
|
||||
}
|
||||
disabledAttributeMessage={
|
||||
disabledAttributeMessage
|
||||
}
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { render } from '@testing-library/react';
|
||||
import {
|
||||
ProductProductAttribute,
|
||||
ProductAttributeTerm,
|
||||
} from '@woocommerce/data';
|
||||
import { ProductAttributeTerm } from '@woocommerce/data';
|
||||
import { createElement } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
|
@ -13,22 +10,6 @@ import { createElement } from '@wordpress/element';
|
|||
*/
|
||||
import { NewAttributeModal } from '../new-attribute-modal';
|
||||
|
||||
let attributeOnChange: ( val: ProductProductAttribute ) => void;
|
||||
jest.mock( '../../attribute-input-field', () => ( {
|
||||
AttributeInputField: ( {
|
||||
onChange,
|
||||
}: {
|
||||
onChange: (
|
||||
value?: Omit<
|
||||
ProductProductAttribute,
|
||||
'position' | 'visible' | 'variation'
|
||||
>
|
||||
) => void;
|
||||
} ) => {
|
||||
attributeOnChange = onChange;
|
||||
return <div>attribute_input_field</div>;
|
||||
},
|
||||
} ) );
|
||||
let attributeTermOnChange: ( val: ProductAttributeTerm[] ) => void;
|
||||
jest.mock( '../../attribute-term-input-field', () => ( {
|
||||
AttributeTermInputField: ( {
|
||||
|
@ -47,40 +28,6 @@ jest.mock( '../../attribute-term-input-field', () => ( {
|
|||
},
|
||||
} ) );
|
||||
|
||||
const attributeList: ProductProductAttribute[] = [
|
||||
{
|
||||
id: 15,
|
||||
name: 'Automotive',
|
||||
position: 0,
|
||||
slug: 'Automotive',
|
||||
visible: true,
|
||||
variation: false,
|
||||
options: [ 'test' ],
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: 'Color',
|
||||
slug: 'Color',
|
||||
position: 2,
|
||||
visible: true,
|
||||
variation: true,
|
||||
options: [
|
||||
'Beige',
|
||||
'black',
|
||||
'Blue',
|
||||
'brown',
|
||||
'Gray',
|
||||
'Green',
|
||||
'mint',
|
||||
'orange',
|
||||
'pink',
|
||||
'Red',
|
||||
'white',
|
||||
'Yellow',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const attributeTermList: ProductAttributeTerm[] = [
|
||||
{
|
||||
id: 23,
|
||||
|
@ -137,28 +84,11 @@ describe( 'NewAttributeModal', () => {
|
|||
selectedAttributeIds={ [] }
|
||||
/>
|
||||
);
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 1 );
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' ).length
|
||||
).toEqual( 1 );
|
||||
} );
|
||||
|
||||
it( 'should enable attribute term field once attribute is selected', () => {
|
||||
const { queryAllByText } = render(
|
||||
<NewAttributeModal
|
||||
onCancel={ () => {} }
|
||||
onAdd={ () => {} }
|
||||
selectedAttributeIds={ [] }
|
||||
/>
|
||||
);
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 1 );
|
||||
attributeOnChange( attributeList[ 0 ] );
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:false' )
|
||||
.length
|
||||
).toEqual( 1 );
|
||||
} );
|
||||
|
||||
it( 'should allow us to add multiple new rows with the attribute fields', () => {
|
||||
const { queryAllByText, queryByRole } = render(
|
||||
<NewAttributeModal
|
||||
|
@ -168,12 +98,12 @@ describe( 'NewAttributeModal', () => {
|
|||
/>
|
||||
);
|
||||
queryByRole( 'button', { name: 'Add another attribute' } )?.click();
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 2 );
|
||||
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' ).length
|
||||
).toEqual( 2 );
|
||||
queryByRole( 'button', { name: 'Add another attribute' } )?.click();
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 3 );
|
||||
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' ).length
|
||||
).toEqual( 3 );
|
||||
|
@ -190,7 +120,7 @@ describe( 'NewAttributeModal', () => {
|
|||
|
||||
queryByRole( 'button', { name: 'Add another attribute' } )?.click();
|
||||
queryByRole( 'button', { name: 'Add another attribute' } )?.click();
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 3 );
|
||||
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' ).length
|
||||
).toEqual( 3 );
|
||||
|
@ -199,7 +129,7 @@ describe( 'NewAttributeModal', () => {
|
|||
|
||||
removeButtons[ 0 ].click();
|
||||
removeButtons[ 1 ].click();
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 1 );
|
||||
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' ).length
|
||||
).toEqual( 1 );
|
||||
|
@ -217,7 +147,7 @@ describe( 'NewAttributeModal', () => {
|
|||
const removeButtons = queryAllByLabelText( 'Remove attribute' );
|
||||
|
||||
removeButtons[ 0 ].click();
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual( 1 );
|
||||
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' ).length
|
||||
).toEqual( 1 );
|
||||
|
@ -239,9 +169,7 @@ describe( 'NewAttributeModal', () => {
|
|||
);
|
||||
addAnotherButton?.click();
|
||||
addAnotherButton?.click();
|
||||
expect( queryAllByText( 'attribute_input_field' ).length ).toEqual(
|
||||
3
|
||||
);
|
||||
|
||||
expect(
|
||||
queryAllByText( 'attribute_term_input_field: disabled:true' )
|
||||
.length
|
||||
|
@ -250,24 +178,6 @@ describe( 'NewAttributeModal', () => {
|
|||
expect( onAddMock ).toHaveBeenCalledWith( [] );
|
||||
} );
|
||||
|
||||
it( 'should not add attribute if no terms were selected', () => {
|
||||
const onAddMock = jest.fn();
|
||||
const { queryByRole } = render(
|
||||
<NewAttributeModal
|
||||
onCancel={ () => {} }
|
||||
onAdd={ onAddMock }
|
||||
selectedAttributeIds={ [] }
|
||||
/>
|
||||
);
|
||||
|
||||
attributeOnChange( {
|
||||
...attributeList[ 0 ],
|
||||
options: [],
|
||||
} );
|
||||
queryByRole( 'button', { name: 'Add attributes' } )?.click();
|
||||
expect( onAddMock ).toHaveBeenCalledWith( [] );
|
||||
} );
|
||||
|
||||
it( 'should add attribute with array of terms', () => {
|
||||
const onAddMock = jest.fn();
|
||||
const { queryByRole } = render(
|
||||
|
@ -278,23 +188,11 @@ describe( 'NewAttributeModal', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
attributeOnChange( attributeList[ 0 ] );
|
||||
attributeTermOnChange( [
|
||||
attributeTermList[ 0 ],
|
||||
attributeTermList[ 1 ],
|
||||
] );
|
||||
queryByRole( 'button', { name: 'Add attributes' } )?.click();
|
||||
|
||||
const onAddMockCalls = onAddMock.mock.calls[ 0 ][ 0 ];
|
||||
|
||||
expect( onAddMockCalls ).toHaveLength( 1 );
|
||||
expect( onAddMockCalls[ 0 ].id ).toEqual( attributeList[ 0 ].id );
|
||||
expect( onAddMockCalls[ 0 ].terms[ 0 ].name ).toEqual(
|
||||
attributeTermList[ 0 ].name
|
||||
);
|
||||
expect( onAddMockCalls[ 0 ].terms[ 1 ].name ).toEqual(
|
||||
attributeTermList[ 1 ].name
|
||||
);
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
@import "components/schedule-publish-modal/style.scss";
|
||||
@import "components/custom-fields/style.scss";
|
||||
@import "components/text-control/style.scss";
|
||||
@import "components/attribute-combobox-field/styles.scss";
|
||||
|
||||
/* Field Blocks */
|
||||
|
||||
|
|
Loading…
Reference in New Issue