[e2e] Skipping 11 tests for the Pressable website (#51123)

* Skipping 11 tests for the Pressable website

* Add changefile(s) from automation for the following project(s): woocommerce

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Jonathan Lane <lanej0@users.noreply.github.com>
This commit is contained in:
Ivan Stojadinov 2024-09-03 23:53:23 +02:00 committed by GitHub
parent 881fd73847
commit 0d65648ed7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 726 additions and 681 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
E2E tests - skipping 11 tests for the Pressable website

View File

@ -512,121 +512,123 @@ test.describe( 'Assembler -> Color Pickers', { tag: '@gutenberg' }, () => {
}
);
test( 'Create "your own" pickers should be visible', async ( {
assemblerPageObject,
baseURL,
}, testInfo ) => {
testInfo.snapshotSuffix = '';
const wordPressVersion = await getInstalledWordPressVersion();
test(
'Create "your own" pickers should be visible',
{ tag: '@skip-on-default-pressable' },
async ( { assemblerPageObject, baseURL }, testInfo ) => {
testInfo.snapshotSuffix = '';
const wordPressVersion = await getInstalledWordPressVersion();
const assembler = await assemblerPageObject.getAssembler();
const colorPicker = assembler.getByText( 'Create your own' );
const assembler = await assemblerPageObject.getAssembler();
const colorPicker = assembler.getByText( 'Create your own' );
await colorPicker.click();
await colorPicker.click();
// Check if Gutenberg is installed
const apiContext = await request.newContext( {
baseURL,
extraHTTPHeaders: {
Authorization: `Basic ${ encodeCredentials(
admin.username,
admin.password
) }`,
cookie: '',
},
} );
const listPluginsResponse = await apiContext.get(
`/wp-json/wp/v2/plugins`,
{
failOnStatusCode: true,
}
);
const pluginsList = await listPluginsResponse.json();
const gutenbergPlugin = pluginsList.find(
( { textdomain } ) => textdomain === 'gutenberg'
);
const mapTypeFeatures = {
background: [ 'solid', 'gradient' ],
text: [],
heading: [ 'text', 'background', 'gradient' ],
button: [ 'text', 'background', 'gradient' ],
link: [ 'default', 'hover' ],
captions: [],
};
const mapTypeFeaturesGutenberg = {
background: [ 'color', 'gradient' ],
text: [],
heading: [ 'text', 'background', 'gradient' ],
button: [ 'text', 'background', 'gradient' ],
link: [ 'default', 'hover' ],
captions: [],
};
const customColorSelector =
'.components-color-palette__custom-color-button';
const gradientColorSelector =
'.components-custom-gradient-picker__gradient-bar-background';
const mapFeatureSelectors = {
solid: customColorSelector,
text: customColorSelector,
background: customColorSelector,
default: customColorSelector,
hover: customColorSelector,
gradient: gradientColorSelector,
};
const mapFeatureSelectorsGutenberg = {
color: customColorSelector,
text: customColorSelector,
background: customColorSelector,
default: customColorSelector,
hover: customColorSelector,
gradient: gradientColorSelector,
};
for ( const type of Object.keys( mapTypeFeatures ) ) {
await assembler
.locator(
'.woocommerce-customize-store__color-panel-container'
)
.getByText( type )
.click();
// eslint-disable-next-line playwright/no-conditional-in-test
if ( gutenbergPlugin || wordPressVersion >= 6.6 ) {
for ( const feature of mapTypeFeaturesGutenberg[ type ] ) {
const container = assembler.locator(
'.block-editor-panel-color-gradient-settings__dropdown-content'
);
await container
.getByRole( 'tab', {
name: feature,
} )
.click();
const selector = mapFeatureSelectorsGutenberg[ feature ];
const featureSelector = container.locator( selector );
await expect( featureSelector ).toBeVisible();
// Check if Gutenberg is installed
const apiContext = await request.newContext( {
baseURL,
extraHTTPHeaders: {
Authorization: `Basic ${ encodeCredentials(
admin.username,
admin.password
) }`,
cookie: '',
},
} );
const listPluginsResponse = await apiContext.get(
`/wp-json/wp/v2/plugins`,
{
failOnStatusCode: true,
}
} else {
for ( const feature of mapTypeFeatures[ type ] ) {
const container = assembler.locator(
'.block-editor-panel-color-gradient-settings__dropdown-content'
);
await container
.getByRole( 'tab', {
name: feature,
} )
.click();
);
const pluginsList = await listPluginsResponse.json();
const gutenbergPlugin = pluginsList.find(
( { textdomain } ) => textdomain === 'gutenberg'
);
const selector = mapFeatureSelectors[ feature ];
const featureSelector = container.locator( selector );
const mapTypeFeatures = {
background: [ 'solid', 'gradient' ],
text: [],
heading: [ 'text', 'background', 'gradient' ],
button: [ 'text', 'background', 'gradient' ],
link: [ 'default', 'hover' ],
captions: [],
};
const mapTypeFeaturesGutenberg = {
background: [ 'color', 'gradient' ],
text: [],
heading: [ 'text', 'background', 'gradient' ],
button: [ 'text', 'background', 'gradient' ],
link: [ 'default', 'hover' ],
captions: [],
};
await expect( featureSelector ).toBeVisible();
const customColorSelector =
'.components-color-palette__custom-color-button';
const gradientColorSelector =
'.components-custom-gradient-picker__gradient-bar-background';
const mapFeatureSelectors = {
solid: customColorSelector,
text: customColorSelector,
background: customColorSelector,
default: customColorSelector,
hover: customColorSelector,
gradient: gradientColorSelector,
};
const mapFeatureSelectorsGutenberg = {
color: customColorSelector,
text: customColorSelector,
background: customColorSelector,
default: customColorSelector,
hover: customColorSelector,
gradient: gradientColorSelector,
};
for ( const type of Object.keys( mapTypeFeatures ) ) {
await assembler
.locator(
'.woocommerce-customize-store__color-panel-container'
)
.getByText( type )
.click();
// eslint-disable-next-line playwright/no-conditional-in-test
if ( gutenbergPlugin || wordPressVersion >= 6.6 ) {
for ( const feature of mapTypeFeaturesGutenberg[ type ] ) {
const container = assembler.locator(
'.block-editor-panel-color-gradient-settings__dropdown-content'
);
await container
.getByRole( 'tab', {
name: feature,
} )
.click();
const selector =
mapFeatureSelectorsGutenberg[ feature ];
const featureSelector = container.locator( selector );
await expect( featureSelector ).toBeVisible();
}
} else {
for ( const feature of mapTypeFeatures[ type ] ) {
const container = assembler.locator(
'.block-editor-panel-color-gradient-settings__dropdown-content'
);
await container
.getByRole( 'tab', {
name: feature,
} )
.click();
const selector = mapFeatureSelectors[ feature ];
const featureSelector = container.locator( selector );
await expect( featureSelector ).toBeVisible();
}
}
}
}
} );
);
} );

View File

@ -96,19 +96,20 @@ test.describe( 'Assembler -> Full composability', { tag: '@gutenberg' }, () => {
}
} );
test( 'The list of categories should be displayed', async ( {
pageObject,
baseURL,
} ) => {
await prepareAssembler( pageObject, baseURL );
const assembler = await pageObject.getAssembler();
test(
'The list of categories should be displayed',
{ tag: '@skip-on-default-pressable' },
async ( { pageObject, baseURL } ) => {
await prepareAssembler( pageObject, baseURL );
const assembler = await pageObject.getAssembler();
const categories = assembler.locator(
'.woocommerce-customize-store__sidebar-homepage-content .components-item-group'
);
const categories = assembler.locator(
'.woocommerce-customize-store__sidebar-homepage-content .components-item-group'
);
await expect( categories ).toHaveCount( 6 );
} );
await expect( categories ).toHaveCount( 6 );
}
);
test( 'Clicking on "Design your homepage" should open the Intro sidebar by default', async ( {
pageObject,

View File

@ -70,20 +70,21 @@ test.describe( 'Assembler -> Homepage', { tag: '@gutenberg' }, () => {
}
} );
test( 'Available homepage should be displayed', async ( {
pageObject,
baseURL,
} ) => {
await prepareAssembler( pageObject, baseURL );
test(
'Available homepage should be displayed',
{ tag: '@skip-on-default-pressable' },
async ( { pageObject, baseURL } ) => {
await prepareAssembler( pageObject, baseURL );
const assembler = await pageObject.getAssembler();
const assembler = await pageObject.getAssembler();
const homepages = assembler.locator(
'.block-editor-block-patterns-list__list-item'
);
const homepages = assembler.locator(
'.block-editor-block-patterns-list__list-item'
);
await expect( homepages ).toHaveCount( 3 );
} );
await expect( homepages ).toHaveCount( 3 );
}
);
test( 'The selected homepage should be focused when is clicked', async ( {
pageObject,
@ -247,31 +248,36 @@ test.describe( 'Homepage tracking banner', () => {
}
} );
test( 'Should show the "Want more patterns?" banner with the PTK API unavailable message', async ( {
baseURL,
pageObject,
page,
} ) => {
await setOption( request, baseURL, 'woocommerce_allow_tracking', 'no' );
test(
'Should show the "Want more patterns?" banner with the PTK API unavailable message',
{ tag: '@skip-on-default-pressable' },
async ( { baseURL, pageObject, page } ) => {
await setOption(
request,
baseURL,
'woocommerce_allow_tracking',
'no'
);
await page.route( '**/wp-json/wc-admin/patterns*', ( route ) => {
route.fulfill( {
status: 500,
await page.route( '**/wp-json/wc-admin/patterns*', ( route ) => {
route.fulfill( {
status: 500,
} );
} );
} );
await prepareAssembler( pageObject, baseURL );
await prepareAssembler( pageObject, baseURL );
const assembler = await pageObject.getAssembler();
await expect(
assembler.getByText( 'Want more patterns?' )
).toBeVisible();
await expect(
assembler.getByText(
"Unfortunately, we're experiencing some technical issues — please come back later to access more patterns."
)
).toBeVisible();
} );
const assembler = await pageObject.getAssembler();
await expect(
assembler.getByText( 'Want more patterns?' )
).toBeVisible();
await expect(
assembler.getByText(
"Unfortunately, we're experiencing some technical issues — please come back later to access more patterns."
)
).toBeVisible();
}
);
test( 'Should show the "Want more patterns?" banner with the Opt-in message when tracking is not allowed', async ( {
pageObject,

View File

@ -219,29 +219,29 @@ test.describe( 'Assembler -> Logo Picker', { tag: '@gutenberg' }, () => {
await expect( emptyLogoLocator ).toBeHidden();
} );
test( 'Enabling the "use as site icon" option should set the image as the site icon', async ( {
page,
assemblerPageObject,
logoPickerPageObject,
} ) => {
const assembler = await assemblerPageObject.getAssembler();
const emptyLogoPicker =
logoPickerPageObject.getEmptyLogoPickerLocator( assembler );
await emptyLogoPicker.click();
await logoPickerPageObject.pickImage( assembler );
await assembler.getByText( 'Use as site icon' ).click();
await logoPickerPageObject.saveLogoSettings( assembler );
test(
'Enabling the "use as site icon" option should set the image as the site icon',
{ tag: '@skip-on-default-pressable' },
async ( { page, assemblerPageObject, logoPickerPageObject } ) => {
const assembler = await assemblerPageObject.getAssembler();
const emptyLogoPicker =
logoPickerPageObject.getEmptyLogoPickerLocator( assembler );
await emptyLogoPicker.click();
await logoPickerPageObject.pickImage( assembler );
await assembler.getByText( 'Use as site icon' ).click();
await logoPickerPageObject.saveLogoSettings( assembler );
// alternative way to verify new site icon on the site
// verifying site icon shown in the new tab is impossible in headless mode
const date = new Date();
const month = ( date.getMonth() + 1 ).toString().padStart( 2, '0' );
await expect(
page.goto(
`/wp-content/uploads/${ date.getFullYear() }/${ month }/image-03-100x100.png`
)
).toBeTruthy();
} );
// alternative way to verify new site icon on the site
// verifying site icon shown in the new tab is impossible in headless mode
const date = new Date();
const month = ( date.getMonth() + 1 ).toString().padStart( 2, '0' );
await expect(
page.goto(
`/wp-content/uploads/${ date.getFullYear() }/${ month }/image-03-100x100.png`
)
).toBeTruthy();
}
);
test( 'The selected image should be visible on the frontend', async ( {
page,

View File

@ -58,21 +58,24 @@ test.describe(
);
} );
test( 'it shows the "offline banner" when the network is offline', async ( {
page,
context,
} ) => {
await page.goto( CUSTOMIZE_STORE_URL );
await expect(
page.locator( 'text=Design your own' )
).toBeVisible();
await context.setOffline( true );
test(
'it shows the "offline banner" when the network is offline',
{ tag: '@skip-on-default-pressable' },
async ( { page, context } ) => {
await page.goto( CUSTOMIZE_STORE_URL );
await expect(
page.locator( 'text=Design your own' )
).toBeVisible();
await context.setOffline( true );
await expect( page.locator( '.offline-banner' ) ).toBeVisible();
await expect(
page.locator( 'text=Looking to design your store using AI?' )
).toBeVisible();
} );
await expect( page.locator( '.offline-banner' ) ).toBeVisible();
await expect(
page.locator(
'text=Looking to design your store using AI?'
)
).toBeVisible();
}
);
test( 'it shows the "no AI" banner on Core when the task is not completed', async ( {
page,

View File

@ -60,17 +60,20 @@ test.describe(
);
} );
test( 'Accessing the transitional page when the CYS flow is not completed should redirect to the Intro page', async ( {
page,
baseURL,
} ) => {
await page.goto( TRANSITIONAL_URL );
test(
'Accessing the transitional page when the CYS flow is not completed should redirect to the Intro page',
{ tag: '@skip-on-default-pressable' },
async ( { page, baseURL } ) => {
await page.goto( TRANSITIONAL_URL );
const locator = page.locator( 'h1:visible' );
await expect( locator ).not.toHaveText( 'Your store looks great!' );
const locator = page.locator( 'h1:visible' );
await expect( locator ).not.toHaveText(
'Your store looks great!'
);
await expect( page.url() ).toBe( `${ baseURL }${ INTRO_URL }` );
} );
await expect( page.url() ).toBe( `${ baseURL }${ INTRO_URL }` );
}
);
test( 'Clicking on "Finish customizing" in the assembler should go to the transitional page', async ( {
pageObject,

View File

@ -16,7 +16,7 @@ const test = baseTest.extend( {
test.describe(
'Transform Classic Cart To Cart Block',
{ tag: [ '@gutenberg', '@services' ] },
{ tag: [ '@gutenberg', '@services', '@skip-on-default-pressable' ] },
() => {
test( 'can transform classic cart to cart block', async ( {
page,

View File

@ -68,105 +68,109 @@ test.describe(
} );
} );
test( 'can transform classic checkout to checkout block', async ( {
page,
api,
testPage,
} ) => {
await goToPageEditor( { page } );
test(
'can transform classic checkout to checkout block',
{ tag: '@skip-on-default-pressable' },
async ( { page, api, testPage } ) => {
await goToPageEditor( { page } );
await closeChoosePatternModal( { page } );
await closeChoosePatternModal( { page } );
await fillPageTitle( page, testPage.title );
const wordPressVersion = await getInstalledWordPressVersion();
await insertBlock( page, 'Classic Checkout', wordPressVersion );
await transformIntoBlocks( page );
await fillPageTitle( page, testPage.title );
const wordPressVersion = await getInstalledWordPressVersion();
await insertBlock( page, 'Classic Checkout', wordPressVersion );
await transformIntoBlocks( page );
// When Gutenberg is active, the canvas is in an iframe
let canvas = await getCanvas( page );
// When Gutenberg is active, the canvas is in an iframe
let canvas = await getCanvas( page );
// Open Settings sidebar if closed
await openEditorSettings( { page } );
// Open Settings sidebar if closed
await openEditorSettings( { page } );
// Activate the terms and conditions checkbox
await canvas.getByLabel( 'Block: Terms and Conditions' ).click();
await page.getByLabel( 'Require checkbox' ).check();
// Activate the terms and conditions checkbox
await canvas
.getByLabel( 'Block: Terms and Conditions' )
.click();
await page.getByLabel( 'Require checkbox' ).check();
await publishPage( page, testPage.title );
await publishPage( page, testPage.title );
// add additional payment option after page creation
const r = await api.put( 'payment_gateways/bacs', {
enabled: true,
} );
expect( r.data.enabled ).toBe( true );
await page.reload();
// add additional payment option after page creation
const r = await api.put( 'payment_gateways/bacs', {
enabled: true,
} );
expect( r.data.enabled ).toBe( true );
await page.reload();
// Mandatory to wait for the editor content, to ensure the iframe is loaded (if Gutenberg is active)
await expect( page.getByLabel( 'Editor content' ) ).toBeVisible();
// Mandatory to wait for the editor content, to ensure the iframe is loaded (if Gutenberg is active)
await expect(
page.getByLabel( 'Editor content' )
).toBeVisible();
// Get the canvas again after the page reload
canvas = await getCanvas( page );
// Get the canvas again after the page reload
canvas = await getCanvas( page );
await expect(
canvas.getByText( 'Direct bank transfer' )
).toBeVisible();
await expect(
canvas.getByText( 'Cash on delivery' )
).toBeVisible();
await expect(
canvas.getByText( 'Direct bank transfer' )
).toBeVisible();
await expect(
canvas.getByText( 'Cash on delivery' )
).toBeVisible();
// add additional shipping methods after page creation
await api.post( `shipping/zones/${ shippingZoneId }/methods`, {
method_id: 'flat_rate',
settings: {
cost: '5.00',
},
} );
await api.post( `shipping/zones/${ shippingZoneId }/methods`, {
method_id: 'local_pickup',
} );
await page.reload();
// add additional shipping methods after page creation
await api.post( `shipping/zones/${ shippingZoneId }/methods`, {
method_id: 'flat_rate',
settings: {
cost: '5.00',
},
} );
await api.post( `shipping/zones/${ shippingZoneId }/methods`, {
method_id: 'local_pickup',
} );
await page.reload();
// verify that added shipping methods are present
// there is issue in blocks: #45747 unable to verify the shipping methods
// please uncomment below when the issue is resolved
// await expect( page.getByLabel( 'Free shipping' ) ).toBeVisible();
// await expect( page.getByLabel( 'Local pickup' ) ).toBeVisible();
// await expect( page.getByLabel( 'Flat rate' ) ).toBeVisible();
// verify that added shipping methods are present
// there is issue in blocks: #45747 unable to verify the shipping methods
// please uncomment below when the issue is resolved
// await expect( page.getByLabel( 'Free shipping' ) ).toBeVisible();
// await expect( page.getByLabel( 'Local pickup' ) ).toBeVisible();
// await expect( page.getByLabel( 'Flat rate' ) ).toBeVisible();
// go to frontend to verify transformed checkout block
// before that add product to cart to be able to visit checkout page
await page.goto( `/cart/?add-to-cart=${ productId }` );
await page.goto( testPage.slug );
await expect(
page.getByRole( 'heading', { name: testPage.title } )
).toBeVisible();
await expect(
page
.getByRole( 'group', { name: 'Contact information' } )
.locator( 'legend' )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-checkout-order-summary-block'
)
).toBeVisible();
await expect(
page.locator( '.wc-block-components-address-form' ).first()
).toBeVisible();
// go to frontend to verify transformed checkout block
// before that add product to cart to be able to visit checkout page
await page.goto( `/cart/?add-to-cart=${ productId }` );
await page.goto( testPage.slug );
await expect(
page.getByRole( 'heading', { name: testPage.title } )
).toBeVisible();
await expect(
page
.getByRole( 'group', { name: 'Contact information' } )
.locator( 'legend' )
).toBeVisible();
await expect(
page.locator(
'.wp-block-woocommerce-checkout-order-summary-block'
)
).toBeVisible();
await expect(
page.locator( '.wc-block-components-address-form' ).first()
).toBeVisible();
// verify existence of the terms & conditions and privacy policy checkbox
await expect(
page.getByText(
'You must accept our Terms and Conditions and Privacy Policy to continue with your purchase.'
)
).toBeVisible();
await expect(
page.locator( '#terms-and-conditions' )
).toBeVisible();
await page.locator( '#terms-and-conditions' ).check();
await expect(
page.locator( '#terms-and-conditions' )
).toBeChecked();
} );
// verify existence of the terms & conditions and privacy policy checkbox
await expect(
page.getByText(
'You must accept our Terms and Conditions and Privacy Policy to continue with your purchase.'
)
).toBeVisible();
await expect(
page.locator( '#terms-and-conditions' )
).toBeVisible();
await page.locator( '#terms-and-conditions' ).check();
await expect(
page.locator( '#terms-and-conditions' )
).toBeChecked();
}
);
}
);

View File

@ -59,365 +59,378 @@ test.describe( 'General tab', { tag: '@gutenberg' }, () => {
'The block product editor is not being tested'
);
test( 'can create a simple product', async ( { page } ) => {
await test.step( 'add new product', async () => {
await page.goto( NEW_EDITOR_ADD_PRODUCT_URL );
} );
test(
'can create a simple product',
{ tag: '@skip-on-default-pressable' },
async ( { page } ) => {
await test.step( 'add new product', async () => {
await page.goto( NEW_EDITOR_ADD_PRODUCT_URL );
} );
await test.step( 'add product name', async () => {
await clickOnTab( 'General', page );
await page
.getByPlaceholder( 'e.g. 12 oz Coffee Mug' )
// Have to use pressSequentially in order for the SKU to be auto-updated
// before we move to the SKU field and attempt to fill it in; otherwise,
// the SKU field can sometimes end up getting auto-updated after we have filled it in,
// wiping out the value we entered.
.pressSequentially( productData.name );
} );
await test.step( 'add product name', async () => {
await clickOnTab( 'General', page );
await page
.getByPlaceholder( 'e.g. 12 oz Coffee Mug' )
// Have to use pressSequentially in order for the SKU to be auto-updated
// before we move to the SKU field and attempt to fill it in; otherwise,
// the SKU field can sometimes end up getting auto-updated after we have filled it in,
// wiping out the value we entered.
.pressSequentially( productData.name );
} );
await test.step( 'add simple product description', async () => {
const descriptionSimpleParagraph = page.locator(
'[data-template-block-id="product-description__content"] > p'
);
await test.step( 'add simple product description', async () => {
const descriptionSimpleParagraph = page.locator(
'[data-template-block-id="product-description__content"] > p'
);
await descriptionSimpleParagraph.fill(
productData.descriptionSimple
);
} );
await descriptionSimpleParagraph.fill(
productData.descriptionSimple
);
} );
await test.step( 'add full product description', async () => {
// Helps to ensure that block toolbar appears, by letting the editor
// know that the user is done typing.
await page.keyboard.press( 'Escape' );
await test.step( 'add full product description', async () => {
// Helps to ensure that block toolbar appears, by letting the editor
// know that the user is done typing.
await page.keyboard.press( 'Escape' );
await page.getByText( 'Full editor' ).click();
await page.getByText( 'Full editor' ).click();
const wordPressVersion = await getInstalledWordPressVersion();
await insertBlock( page, 'Heading', wordPressVersion );
const wordPressVersion =
await getInstalledWordPressVersion();
await insertBlock( page, 'Heading', wordPressVersion );
const editorCanvasLocator = page.frameLocator(
'iframe[name="editor-canvas"]'
);
const editorCanvasLocator = page.frameLocator(
'iframe[name="editor-canvas"]'
);
await editorCanvasLocator
.locator( '[data-title="Heading"]' )
.fill( productData.descriptionTitle );
await editorCanvasLocator
.locator( '[data-title="Heading"]' )
.fill( productData.descriptionTitle );
await editorCanvasLocator
.locator( '[data-title="Heading"]' )
.blur();
await editorCanvasLocator
.locator( '[data-title="Heading"]' )
.blur();
await insertBlock( page, 'Paragraph', wordPressVersion );
await insertBlock( page, 'Paragraph', wordPressVersion );
await editorCanvasLocator
.locator( '[data-title="Paragraph"]' )
.last()
.fill( productData.descriptionParagraph );
await editorCanvasLocator
.locator( '[data-title="Paragraph"]' )
.last()
.fill( productData.descriptionParagraph );
await page.getByRole( 'button', { name: 'Done' } ).click();
} );
await page.getByRole( 'button', { name: 'Done' } ).click();
} );
await test.step( 'verify full product description', async () => {
const previewContainerIframe = page
.locator( '.block-editor-block-preview__container' )
.frameLocator( 'iframe[title="Editor canvas"]' );
await test.step( 'verify full product description', async () => {
const previewContainerIframe = page
.locator( '.block-editor-block-preview__container' )
.frameLocator( 'iframe[title="Editor canvas"]' );
const descriptionTitle = previewContainerIframe.locator(
'[data-title="Heading"]'
);
const descriptionInitialParagraph = previewContainerIframe
.locator( '[data-title="Paragraph"]' )
.first();
const descriptionSecondParagraph = previewContainerIframe
.locator( '[data-title="Paragraph"]' )
.last();
const descriptionTitle = previewContainerIframe.locator(
'[data-title="Heading"]'
);
const descriptionInitialParagraph = previewContainerIframe
.locator( '[data-title="Paragraph"]' )
.first();
const descriptionSecondParagraph = previewContainerIframe
.locator( '[data-title="Paragraph"]' )
.last();
await expect( descriptionTitle ).toHaveText(
productData.descriptionTitle
);
await expect( descriptionInitialParagraph ).toHaveText(
productData.descriptionSimple
);
await expect( descriptionSecondParagraph ).toHaveText(
productData.descriptionParagraph
);
await expect( descriptionTitle ).toHaveText(
productData.descriptionTitle
);
await expect( descriptionInitialParagraph ).toHaveText(
productData.descriptionSimple
);
await expect( descriptionSecondParagraph ).toHaveText(
productData.descriptionParagraph
);
await descriptionTitle.click();
await descriptionTitle.click();
await expect(
page.getByText( 'Edit in full editor' )
).toBeVisible();
} );
await expect(
page.getByText( 'Edit in full editor' )
).toBeVisible();
} );
await test.step( 'add product summary', async () => {
await page
.locator(
'[data-template-block-id="basic-details"] .components-summary-control'
)
.last()
.fill( productData.summary );
await test.step( 'add product summary', async () => {
await page
.locator(
'[data-template-block-id="basic-details"] .components-summary-control'
)
.last()
.fill( productData.summary );
// Blur the summary field to hide the toolbar before clicking on the regular price field.
await page
.locator(
'[data-template-block-id="basic-details"] .components-summary-control'
)
.last()
.blur();
} );
// Blur the summary field to hide the toolbar before clicking on the regular price field.
await page
.locator(
'[data-template-block-id="basic-details"] .components-summary-control'
)
.last()
.blur();
} );
await test.step( 'add product price', async () => {
const regularPrice = page
.locator( 'input[name="regular_price"]' )
.first();
await regularPrice.waitFor( { state: 'visible' } );
await regularPrice.click();
await regularPrice.fill( productData.productPrice );
await test.step( 'add product price', async () => {
const regularPrice = page
.locator( 'input[name="regular_price"]' )
.first();
await regularPrice.waitFor( { state: 'visible' } );
await regularPrice.click();
await regularPrice.fill( productData.productPrice );
const salePrice = page
.locator( 'input[name="sale_price"]' )
.first();
await salePrice.waitFor( { state: 'visible' } );
await salePrice.click();
await salePrice.fill( productData.salePrice );
} );
const salePrice = page
.locator( 'input[name="sale_price"]' )
.first();
await salePrice.waitFor( { state: 'visible' } );
await salePrice.click();
await salePrice.fill( productData.salePrice );
} );
await test.step( 'add custom fields', async () => {
await clickOnTab( 'Organization', page );
await test.step( 'add custom fields', async () => {
await clickOnTab( 'Organization', page );
const customFieldsAddNewButton = page
.getByLabel( 'Block: Product custom fields toggle control' )
.getByRole( 'button', { name: 'Add new' } );
const customFieldsAddNewButton = page
.getByLabel(
'Block: Product custom fields toggle control'
)
.getByRole( 'button', { name: 'Add new' } );
// When re-running the test without resetting the env,
// the custom fields toggle might be already checked,
// so we need to check if the "Add new" button is already visible.
//
// eslint-disable-next-line playwright/no-conditional-in-test
if ( ! ( await customFieldsAddNewButton.isVisible() ) ) {
// Toggle the "Show custom fields" so that the "Add new" button is visible
const customFieldsToggle = page.getByRole( 'checkbox', {
name: 'Show custom fields',
} );
await customFieldsToggle.scrollIntoViewIfNeeded();
// click() is used instead of check() because
// Playwright sometimes has issues with custom checkboxes:
// - https://github.com/microsoft/playwright/issues/13470
// - https://github.com/microsoft/playwright/issues/20893
// - https://github.com/microsoft/playwright/issues/27016
// When re-running the test without resetting the env,
// the custom fields toggle might be already checked,
// so we need to check if the "Add new" button is already visible.
//
// eslint-disable-next-line playwright/no-conditional-in-test
if ( ! ( await customFieldsToggle.isChecked() ) ) {
await customFieldsToggle.click();
if ( ! ( await customFieldsAddNewButton.isVisible() ) ) {
// Toggle the "Show custom fields" so that the "Add new" button is visible
const customFieldsToggle = page.getByRole( 'checkbox', {
name: 'Show custom fields',
} );
await customFieldsToggle.scrollIntoViewIfNeeded();
// click() is used instead of check() because
// Playwright sometimes has issues with custom checkboxes:
// - https://github.com/microsoft/playwright/issues/13470
// - https://github.com/microsoft/playwright/issues/20893
// - https://github.com/microsoft/playwright/issues/27016
//
// eslint-disable-next-line playwright/no-conditional-in-test
if ( ! ( await customFieldsToggle.isChecked() ) ) {
await customFieldsToggle.click();
}
await customFieldsToggle.isEnabled();
}
await customFieldsToggle.isEnabled();
}
await expect( customFieldsAddNewButton ).toBeVisible();
await expect( customFieldsAddNewButton ).toBeVisible();
await customFieldsAddNewButton.click();
await customFieldsAddNewButton.click();
// Add custom fields modal
const modal = page.locator(
'.woocommerce-product-custom-fields__create-modal'
);
// Add custom fields modal
const modal = page.locator(
'.woocommerce-product-custom-fields__create-modal'
);
await expect(
modal.getByText( 'Add custom fields' )
).toBeVisible();
await expect(
modal.getByText( 'Add custom fields' )
).toBeVisible();
const nameInput = modal.getByLabel( 'Name' );
// Have to use pressSequentially in order to get the dropdown to show up and be able to select the option
await nameInput.pressSequentially(
productData.customFields[ 0 ].name
);
await expect(
modal.getByRole(
'option',
const nameInput = modal.getByLabel( 'Name' );
// Have to use pressSequentially in order to get the dropdown to show up and be able to select the option
await nameInput.pressSequentially(
productData.customFields[ 0 ].name
)
).toBeVisible();
);
await nameInput.press( 'Enter' );
await expect(
modal.getByRole(
'option',
productData.customFields[ 0 ].name
)
).toBeVisible();
const valueInput = modal.getByLabel( 'Value' );
await valueInput.fill( productData.customFields[ 0 ].value );
await nameInput.press( 'Enter' );
await modal
.getByRole( 'button', { name: 'Add', exact: true } )
.click();
const valueInput = modal.getByLabel( 'Value' );
await valueInput.fill(
productData.customFields[ 0 ].value
);
await expect(
modal.getByText( 'Add custom fields' )
).toBeHidden();
await modal
.getByRole( 'button', { name: 'Add', exact: true } )
.click();
await expect(
page.getByText( productData.customFields[ 0 ].name )
).toBeVisible();
await expect(
page.getByText( productData.customFields[ 0 ].value )
).toBeVisible();
} );
await expect(
modal.getByText( 'Add custom fields' )
).toBeHidden();
await test.step( 'add inventory details', async () => {
await clickOnTab( 'Inventory', page );
await expect(
page.getByText( productData.customFields[ 0 ].name )
).toBeVisible();
await expect(
page.getByText( productData.customFields[ 0 ].value )
).toBeVisible();
} );
await page
.getByLabel( 'SKU (Stock Keeping Unit)' )
.fill( productData.sku );
await page
.getByLabel( 'GTIN, UPC, EAN, or ISBN' )
.fill( productData.gtin );
} );
await test.step( 'add inventory details', async () => {
await clickOnTab( 'Inventory', page );
await test.step( 'add shipping details', async () => {
await clickOnTab( 'Shipping', page );
await page
.getByLabel( 'SKU (Stock Keeping Unit)' )
.fill( productData.sku );
await page
.getByLabel( 'GTIN, UPC, EAN, or ISBN' )
.fill( productData.gtin );
} );
// Shipping class
await page
.getByLabel( 'Shipping class', { exact: true } )
//.locator( 'select[name="shipping_class"]' )
.selectOption( 'Add new shipping class' );
await test.step( 'add shipping details', async () => {
await clickOnTab( 'Shipping', page );
// New shipping class modal
const modal = page.locator(
'.woocommerce-add-new-shipping-class-modal'
);
// Shipping class
await page
.getByLabel( 'Shipping class', { exact: true } )
//.locator( 'select[name="shipping_class"]' )
.selectOption( 'Add new shipping class' );
await expect(
modal.getByText( 'New shipping class' )
).toBeVisible();
// New shipping class modal
const modal = page.locator(
'.woocommerce-add-new-shipping-class-modal'
);
await modal
.getByLabel( 'Name (Required)' )
.fill( productData.shipping.shippingClassName );
await expect(
modal.getByText( 'New shipping class' )
).toBeVisible();
await modal.getByText( 'Add' ).click();
await modal
.getByLabel( 'Name (Required)' )
.fill( productData.shipping.shippingClassName );
await expect(
modal.getByText( 'New shipping class' )
).toBeHidden();
await modal.getByText( 'Add' ).click();
await expect(
page.getByLabel( 'Shipping class', { exact: true } )
).toHaveValue( productData.shipping.shippingClassName );
await expect(
modal.getByText( 'New shipping class' )
).toBeHidden();
// Shipping dimensions
await page
.getByLabel( 'Width A' )
.fill( productData.shipping.width );
await page
.getByLabel( 'Length B' )
.fill( productData.shipping.length );
await page
.getByLabel( 'Height C' )
.fill( productData.shipping.height );
await page
.getByLabel( 'Weight' )
.fill( productData.shipping.weight );
} );
await expect(
page.getByLabel( 'Shipping class', { exact: true } )
).toHaveValue( productData.shipping.shippingClassName );
await test.step( 'publish the product', async () => {
await page
.locator( '.woocommerce-product-header__actions' )
.getByRole( 'button', {
name: 'Publish',
} )
.click();
// Shipping dimensions
await page
.getByLabel( 'Width A' )
.fill( productData.shipping.width );
await page
.getByLabel( 'Length B' )
.fill( productData.shipping.length );
await page
.getByLabel( 'Height C' )
.fill( productData.shipping.height );
await page
.getByLabel( 'Weight' )
.fill( productData.shipping.weight );
} );
await expect(
page.getByLabel( 'Dismiss this notice' )
).toContainText( 'Product published' );
await test.step( 'publish the product', async () => {
await page
.locator( '.woocommerce-product-header__actions' )
.getByRole( 'button', {
name: 'Publish',
} )
.click();
const title = page.locator(
'.woocommerce-product-header__title'
);
await expect(
page.getByLabel( 'Dismiss this notice' )
).toContainText( 'Product published' );
// Save product ID
const productIdRegex = /product%2F(\d+)/;
const url = page.url();
const productIdMatch = productIdRegex.exec( url );
// This isn't really a conditional branch in the test;
// just making sure we don't blow up if the regex doesn't match
// (it will be caught in the expect below).
// eslint-disable-next-line playwright/no-conditional-in-test
productId = productIdMatch ? productIdMatch[ 1 ] : null;
const title = page.locator(
'.woocommerce-product-header__title'
);
expect( productId ).toBeDefined();
await expect( title ).toHaveText( productData.name );
} );
// Save product ID
const productIdRegex = /product%2F(\d+)/;
const url = page.url();
const productIdMatch = productIdRegex.exec( url );
// This isn't really a conditional branch in the test;
// just making sure we don't blow up if the regex doesn't match
// (it will be caught in the expect below).
// eslint-disable-next-line playwright/no-conditional-in-test
productId = productIdMatch ? productIdMatch[ 1 ] : null;
// Note for future refactoring: It would be good to reuse the verification step
// from product-create-simple.spec.js, as both tests are just verifying that the
// product was created correctly by looking at the front end.
await test.step( 'verify the saved product in frontend', async () => {
const permalink = await page
.locator( '.product-details-section__product-link a' )
.getAttribute( 'href' );
expect( productId ).toBeDefined();
await expect( title ).toHaveText( productData.name );
} );
await page.goto( permalink );
// Note for future refactoring: It would be good to reuse the verification step
// from product-create-simple.spec.js, as both tests are just verifying that the
// product was created correctly by looking at the front end.
await test.step( 'verify the saved product in frontend', async () => {
const permalink = await page
.locator( '.product-details-section__product-link a' )
.getAttribute( 'href' );
// Verify product name
await expect(
page.getByRole( 'heading', {
name: productData.name,
} )
).toBeVisible();
await page.goto( permalink );
// Verify price
await expect(
page.getByText( productData.productPrice ).first()
).toBeVisible();
await expect(
page.getByText( productData.salePrice ).first()
).toBeVisible();
// Verify product name
await expect(
page.getByRole( 'heading', {
name: productData.name,
} )
).toBeVisible();
// Verify summary
await expect(
page.getByText( productData.summary )
).toBeVisible();
// Verify price
await expect(
page.getByText( productData.productPrice ).first()
).toBeVisible();
await expect(
page.getByText( productData.salePrice ).first()
).toBeVisible();
// Verify description
await page.getByRole( 'tab', { name: 'Description' } ).click();
// Verify summary
await expect(
page.getByText( productData.summary )
).toBeVisible();
await expect(
page.getByText( productData.descriptionTitle )
).toBeVisible();
await expect(
page.getByText( productData.descriptionSimple )
).toBeVisible();
await expect(
page.getByText( productData.descriptionParagraph )
).toBeVisible();
// Verify description
await page
.getByRole( 'tab', { name: 'Description' } )
.click();
// Verify inventory details
await expect(
page.getByText( `SKU: ${ productData.sku }` )
).toBeVisible();
// Note: GTIN is not displayed in the front end in the theme used in the test
await expect(
page.getByText( productData.descriptionTitle )
).toBeVisible();
await expect(
page.getByText( productData.descriptionSimple )
).toBeVisible();
await expect(
page.getByText( productData.descriptionParagraph )
).toBeVisible();
// Note: Shipping class is not displayed in the front end in the theme used in the test
// Verify inventory details
await expect(
page.getByText( `SKU: ${ productData.sku }` )
).toBeVisible();
// Note: GTIN is not displayed in the front end in the theme used in the test
// Verify shipping dimensions
await page
.getByRole( 'tab', { name: 'Additional information' } )
.click();
// Note: Shipping class is not displayed in the front end in the theme used in the test
await expect(
page.getByText( `Weight ${ productData.shipping.weight }` )
).toBeVisible();
await expect(
page.getByText(
`Dimensions ${ productData.shipping.length } × ${ productData.shipping.width } × ${ productData.shipping.height }`
)
).toBeVisible();
} );
} );
// Verify shipping dimensions
await page
.getByRole( 'tab', { name: 'Additional information' } )
.click();
await expect(
page.getByText(
`Weight ${ productData.shipping.weight }`
)
).toBeVisible();
await expect(
page.getByText(
`Dimensions ${ productData.shipping.length } × ${ productData.shipping.width } × ${ productData.shipping.height }`
)
).toBeVisible();
} );
}
);
test( 'can not create a product with duplicated SKU', async ( {
page,

View File

@ -68,130 +68,139 @@ test.describe( 'General tab', { tag: '@gutenberg' }, () => {
'The block product editor is not being tested'
);
test( 'can create a product with linked products', async ( {
page,
} ) => {
await page.goto( NEW_EDITOR_ADD_PRODUCT_URL );
await clickOnTab( 'General', page );
await page
.getByPlaceholder( 'e.g. 12 oz Coffee Mug' )
.fill( productData.name );
await page
.locator(
'[data-template-block-id="basic-details"] .components-summary-control'
)
.last()
.fill( productData.summary );
test(
'can create a product with linked products',
{ tag: '@skip-on-default-pressable' },
async ( { page } ) => {
await page.goto( NEW_EDITOR_ADD_PRODUCT_URL );
await clickOnTab( 'General', page );
await page
.getByPlaceholder( 'e.g. 12 oz Coffee Mug' )
.fill( productData.name );
await page
.locator(
'[data-template-block-id="basic-details"] .components-summary-control'
)
.last()
.fill( productData.summary );
// Include in category
await clickOnTab( 'Organization', page );
const waitForCategoriesResponse = page.waitForResponse(
( response ) =>
response.url().includes( '/wp-json/wp/v2/product_cat' ) &&
response.status() === 200
);
await page.getByLabel( 'Categories' ).click();
await waitForCategoriesResponse;
await page.getByLabel( categoryName ).check();
await page.getByLabel( `Remove Uncategorized` ).click();
await expect(
page.getByLabel( `Remove ${ categoryName }` )
).toBeVisible();
// Include in category
await clickOnTab( 'Organization', page );
const waitForCategoriesResponse = page.waitForResponse(
( response ) =>
response
.url()
.includes( '/wp-json/wp/v2/product_cat' ) &&
response.status() === 200
);
await page.getByLabel( 'Categories' ).click();
await waitForCategoriesResponse;
await page.getByLabel( categoryName ).check();
await page.getByLabel( `Remove Uncategorized` ).click();
await expect(
page.getByLabel( `Remove ${ categoryName }` )
).toBeVisible();
const waitForProductsSearchResponse = page.waitForResponse(
( response ) =>
response
.url()
.includes( '/wp-json/wc/v3/products?search' ) &&
response.status() === 200
);
await clickOnTab( 'Linked products', page );
await waitForProductsSearchResponse;
const waitForProductsSearchResponse = page.waitForResponse(
( response ) =>
response
.url()
.includes( '/wp-json/wc/v3/products?search' ) &&
response.status() === 200
);
await clickOnTab( 'Linked products', page );
await waitForProductsSearchResponse;
await expect(
page.getByRole( 'heading', {
name: 'Cross-sells',
} )
).toBeVisible();
await expect(
page.getByRole( 'heading', {
name: 'Cross-sells',
} )
).toBeVisible();
await page
.locator(
'.wp-block-woocommerce-product-linked-list-field__form-group-content'
)
.first()
.getByRole( 'combobox' )
.fill( productName );
await page
.locator(
'.wp-block-woocommerce-product-linked-list-field__form-group-content'
)
.first()
.getByRole( 'combobox' )
.fill( productName );
await page.getByText( linkedProductsData[ 0 ].name ).click();
await page.getByText( linkedProductsData[ 0 ].name ).click();
const chooseProductsResponsePromise = page.waitForResponse(
( response ) =>
response
.url()
.includes(
'/wp-json/wc/v3/products/suggested-products'
) && response.status() === 200
);
const chooseProductsResponsePromise = page.waitForResponse(
( response ) =>
response
.url()
.includes(
'/wp-json/wc/v3/products/suggested-products'
) && response.status() === 200
);
await page.getByText( 'Choose products for me' ).first().click();
await chooseProductsResponsePromise;
await page
.getByText( 'Choose products for me' )
.first()
.click();
await chooseProductsResponsePromise;
await expect(
page.getByRole( 'row', { name: productName } )
).toHaveCount( 4 );
await expect(
page.getByRole( 'row', { name: productName } )
).toHaveCount( 4 );
const upsellsRows = page.locator(
'div.woocommerce-product-list div[role="table"] div[role="rowgroup"] div[role="row"]'
);
const upsellsRows = page.locator(
'div.woocommerce-product-list div[role="table"] div[role="rowgroup"] div[role="row"]'
);
await expect( upsellsRows ).toHaveCount( 4 );
await expect( upsellsRows ).toHaveCount( 4 );
await page
.locator(
'.wp-block-woocommerce-product-linked-list-field__form-group-content'
)
.last()
.getByRole( 'combobox' )
.fill( linkedProductsData[ 1 ].name );
await page
.locator(
'.wp-block-woocommerce-product-linked-list-field__form-group-content'
)
.last()
.getByRole( 'combobox' )
.fill( linkedProductsData[ 1 ].name );
await page
.getByText( linkedProductsData[ 1 ].name )
.first()
.click();
await page
.getByText( linkedProductsData[ 1 ].name )
.first()
.click();
await page
.locator( '.woocommerce-product-header__actions' )
.getByRole( 'button', {
name: 'Publish',
} )
.click();
await page
.locator( '.woocommerce-product-header__actions' )
.getByRole( 'button', {
name: 'Publish',
} )
.click();
await expect(
page.getByLabel( 'Dismiss this notice' )
).toContainText( 'Product published' );
await expect(
page.getByLabel( 'Dismiss this notice' )
).toContainText( 'Product published' );
const title = page.locator( '.woocommerce-product-header__title' );
const title = page.locator(
'.woocommerce-product-header__title'
);
// Save product ID
const productIdRegex = /product%2F(\d+)/;
const url = page.url();
const productIdMatch = productIdRegex.exec( url );
productId = productIdMatch ? productIdMatch[ 1 ] : null;
// Save product ID
const productIdRegex = /product%2F(\d+)/;
const url = page.url();
const productIdMatch = productIdRegex.exec( url );
productId = productIdMatch ? productIdMatch[ 1 ] : null;
await expect( productId ).toBeDefined();
await expect( title ).toHaveText( productData.name );
await expect( productId ).toBeDefined();
await expect( title ).toHaveText( productData.name );
await page.goto( `/?post_type=product&p=${ productId }` );
await page.goto( `/?post_type=product&p=${ productId }` );
await expect(
page.getByRole( 'heading', { name: productData.name } )
).toBeVisible();
await expect(
page.getByRole( 'heading', { name: productData.name } )
).toBeVisible();
const productsList = page.locator(
'section.upsells.products ul > li'
);
const productsList = page.locator(
'section.upsells.products ul > li'
);
await expect( productsList ).toHaveCount( 4 );
} );
await expect( productsList ).toHaveCount( 4 );
}
);
} );
} );