[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 ( { test(
assemblerPageObject, 'Create "your own" pickers should be visible',
baseURL, { tag: '@skip-on-default-pressable' },
}, testInfo ) => { async ( { assemblerPageObject, baseURL }, testInfo ) => {
testInfo.snapshotSuffix = ''; testInfo.snapshotSuffix = '';
const wordPressVersion = await getInstalledWordPressVersion(); const wordPressVersion = await getInstalledWordPressVersion();
const assembler = await assemblerPageObject.getAssembler(); const assembler = await assemblerPageObject.getAssembler();
const colorPicker = assembler.getByText( 'Create your own' ); const colorPicker = assembler.getByText( 'Create your own' );
await colorPicker.click(); await colorPicker.click();
// Check if Gutenberg is installed // Check if Gutenberg is installed
const apiContext = await request.newContext( { const apiContext = await request.newContext( {
baseURL, baseURL,
extraHTTPHeaders: { extraHTTPHeaders: {
Authorization: `Basic ${ encodeCredentials( Authorization: `Basic ${ encodeCredentials(
admin.username, admin.username,
admin.password admin.password
) }`, ) }`,
cookie: '', cookie: '',
}, },
} ); } );
const listPluginsResponse = await apiContext.get( const listPluginsResponse = await apiContext.get(
`/wp-json/wp/v2/plugins`, `/wp-json/wp/v2/plugins`,
{ {
failOnStatusCode: true, 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();
} }
} else { );
for ( const feature of mapTypeFeatures[ type ] ) { const pluginsList = await listPluginsResponse.json();
const container = assembler.locator( const gutenbergPlugin = pluginsList.find(
'.block-editor-panel-color-gradient-settings__dropdown-content' ( { textdomain } ) => textdomain === 'gutenberg'
); );
await container
.getByRole( 'tab', {
name: feature,
} )
.click();
const selector = mapFeatureSelectors[ feature ]; const mapTypeFeatures = {
const featureSelector = container.locator( selector ); 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 ( { test(
pageObject, 'The list of categories should be displayed',
baseURL, { tag: '@skip-on-default-pressable' },
} ) => { async ( { pageObject, baseURL } ) => {
await prepareAssembler( pageObject, baseURL ); await prepareAssembler( pageObject, baseURL );
const assembler = await pageObject.getAssembler(); const assembler = await pageObject.getAssembler();
const categories = assembler.locator( const categories = assembler.locator(
'.woocommerce-customize-store__sidebar-homepage-content .components-item-group' '.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 ( { test( 'Clicking on "Design your homepage" should open the Intro sidebar by default', async ( {
pageObject, pageObject,

View File

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

View File

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

View File

@ -58,21 +58,24 @@ test.describe(
); );
} ); } );
test( 'it shows the "offline banner" when the network is offline', async ( { test(
page, 'it shows the "offline banner" when the network is offline',
context, { tag: '@skip-on-default-pressable' },
} ) => { async ( { page, context } ) => {
await page.goto( CUSTOMIZE_STORE_URL ); await page.goto( CUSTOMIZE_STORE_URL );
await expect( await expect(
page.locator( 'text=Design your own' ) page.locator( 'text=Design your own' )
).toBeVisible(); ).toBeVisible();
await context.setOffline( true ); await context.setOffline( true );
await expect( page.locator( '.offline-banner' ) ).toBeVisible(); await expect( page.locator( '.offline-banner' ) ).toBeVisible();
await expect( await expect(
page.locator( 'text=Looking to design your store using AI?' ) page.locator(
).toBeVisible(); '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 ( { test( 'it shows the "no AI" banner on Core when the task is not completed', async ( {
page, 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 ( { test(
page, 'Accessing the transitional page when the CYS flow is not completed should redirect to the Intro page',
baseURL, { tag: '@skip-on-default-pressable' },
} ) => { async ( { page, baseURL } ) => {
await page.goto( TRANSITIONAL_URL ); await page.goto( TRANSITIONAL_URL );
const locator = page.locator( 'h1:visible' ); const locator = page.locator( 'h1:visible' );
await expect( locator ).not.toHaveText( 'Your store looks great!' ); 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 ( { test( 'Clicking on "Finish customizing" in the assembler should go to the transitional page', async ( {
pageObject, pageObject,

View File

@ -16,7 +16,7 @@ const test = baseTest.extend( {
test.describe( test.describe(
'Transform Classic Cart To Cart Block', '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 ( { test( 'can transform classic cart to cart block', async ( {
page, page,

View File

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

View File

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

View File

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