* Add eslint playwright plugin configuration

* replace networkidle with commit

* address  Unnecessary await expression. This method does not return a Promise error

* address 'Unexpected usage of not.toBeVisible(). Use toBeHidden() instead' error

* address 'Unexpected use of the .skip()  annotation.' error

* address 'toHaveCount' must be awaited or returned' error

* address ''page' is defined but never used '

* address ''toBeVisible' must be awaited or returned'

* address 'Unexpected use of element handles'

* address 'Unnecessary await expression. This method does not return a Promise'

* address 'Test has no assertions'

* address 'Unexpected use of page.waitForTimeout()'

* address 'Avoid having conditionals in tests'
This commit is contained in:
Luigi Teschio 2023-08-08 15:25:45 +02:00 committed by GitHub
parent 5a84f82425
commit be1cefc4b4
26 changed files with 192 additions and 155 deletions

View File

@ -144,6 +144,7 @@
"eslint-import-resolver-typescript": "3.2.4",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-playwright": "0.15.3",
"eslint-plugin-woocommerce": "file:bin/eslint-plugin-woocommerce",
"eslint-plugin-you-dont-need-lodash-underscore": "6.12.0",
"expect-puppeteer": "6.1.1",
@ -17255,6 +17256,21 @@
"node": ">=12"
}
},
"node_modules/@wordpress/eslint-plugin/node_modules/eslint-plugin-playwright": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.8.0.tgz",
"integrity": "sha512-9uJH25m6H3jwU5O7bHD5M8cLx46L72EnIUe3dZqTox6M+WzOFzeUWaDJHHCdLGXZ8XlAU4mbCZnP7uhjKepfRA==",
"dev": true,
"peerDependencies": {
"eslint": ">=7",
"eslint-plugin-jest": ">=24"
},
"peerDependenciesMeta": {
"eslint-plugin-jest": {
"optional": true
}
}
},
"node_modules/@wordpress/eslint-plugin/node_modules/globals": {
"version": "13.13.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
@ -27916,13 +27932,13 @@
}
},
"node_modules/eslint-plugin-playwright": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.8.0.tgz",
"integrity": "sha512-9uJH25m6H3jwU5O7bHD5M8cLx46L72EnIUe3dZqTox6M+WzOFzeUWaDJHHCdLGXZ8XlAU4mbCZnP7uhjKepfRA==",
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.15.3.tgz",
"integrity": "sha512-LQMW5y0DLK5Fnpya7JR1oAYL2/7Y9wDiYw6VZqlKqcRGSgjbVKNqxraphk7ra1U3Bb5EK444xMgUlQPbMg2M1g==",
"dev": true,
"peerDependencies": {
"eslint": ">=7",
"eslint-plugin-jest": ">=24"
"eslint-plugin-jest": ">=25"
},
"peerDependenciesMeta": {
"eslint-plugin-jest": {
@ -66943,6 +66959,13 @@
"integrity": "sha512-M4WQ0C4zCfMWyCmK40git3rfPdNkRwg5boGjoTL4LSdhrY+rtchFAtfOHS9KovAZ5ZzTB0gyZsCu/QKZlPClog==",
"dev": true
},
"eslint-plugin-playwright": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.8.0.tgz",
"integrity": "sha512-9uJH25m6H3jwU5O7bHD5M8cLx46L72EnIUe3dZqTox6M+WzOFzeUWaDJHHCdLGXZ8XlAU4mbCZnP7uhjKepfRA==",
"dev": true,
"requires": {}
},
"globals": {
"version": "13.13.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz",
@ -75263,9 +75286,9 @@
}
},
"eslint-plugin-playwright": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.8.0.tgz",
"integrity": "sha512-9uJH25m6H3jwU5O7bHD5M8cLx46L72EnIUe3dZqTox6M+WzOFzeUWaDJHHCdLGXZ8XlAU4mbCZnP7uhjKepfRA==",
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.15.3.tgz",
"integrity": "sha512-LQMW5y0DLK5Fnpya7JR1oAYL2/7Y9wDiYw6VZqlKqcRGSgjbVKNqxraphk7ra1U3Bb5EK444xMgUlQPbMg2M1g==",
"dev": true,
"requires": {}
},

View File

@ -192,6 +192,7 @@
"eslint-import-resolver-typescript": "3.2.4",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-playwright": "0.15.3",
"eslint-plugin-woocommerce": "file:bin/eslint-plugin-woocommerce",
"eslint-plugin-you-dont-need-lodash-underscore": "6.12.0",
"expect-puppeteer": "6.1.1",

View File

@ -0,0 +1,24 @@
const config = {
extends: [ '../../.eslintrc.js', 'plugin:playwright/recommended' ],
rules: {
'playwright/expect-expect': 'error',
'playwright/max-nested-describe': 'error',
'playwright/missing-playwright-await': 'error',
'playwright/no-conditional-in-test': 'error',
'playwright/no-element-handle': 'error',
'playwright/no-eval': 'error',
'playwright/no-focused-test': 'error',
'playwright/no-force-option': 'error',
'playwright/no-nested-step': 'error',
'playwright/no-networkidle': 'error',
'playwright/no-page-pause': 'error',
'playwright/no-skipped-test': 'error',
'playwright/no-useless-await': 'error',
'playwright/no-useless-not': 'error',
'playwright/no-wait-for-timeout': 'error',
'playwright/prefer-web-first-assertions': 'error',
'playwright/valid-expect': 'error',
},
};
module.exports = config;

View File

@ -44,14 +44,14 @@ const loginAsCustomer = async ( config: FullConfig ) => {
for ( let i = 0; i < customerRetries; i++ ) {
try {
await customerPage.goto( `/wp-admin`, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
await customerPage.fill( 'input[name="log"]', customer.username );
await customerPage.fill( 'input[name="pwd"]', customer.password );
await customerPage.click( 'text=Log In' );
await customerPage.goto( `/my-account`, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
await customerPage
@ -90,7 +90,7 @@ const prepareAttributes = async ( config: FullConfig ) => {
const context = await browser.newContext( contextOptions );
const page = await context.newPage();
await page.goto( `/wp-admin`, { waitUntil: 'networkidle' } );
await page.goto( `/wp-admin`, { waitUntil: 'commit' } );
await page.fill( 'input[name="log"]', admin.username );
await page.fill( 'input[name="pwd"]', admin.password );
await page.click( 'text=Log In' );
@ -105,7 +105,7 @@ const prepareAttributes = async ( config: FullConfig ) => {
} );
await page.goto( '/wp-admin/admin.php?page=wc-status&tab=tools', {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
await page.click( '.regenerate_product_attributes_lookup_table input' );

View File

@ -8,9 +8,11 @@ test.describe( 'Filter by Attributes Block - with All products Block', () => {
page,
} ) => {
await page.goto(
'/active-filters-block/?filter_color=blue&query_type_color=or'
'/active-filters-block/?filter_color=blue&query_type_color=or',
{
waitUntil: 'commit',
}
);
await page.waitForLoadState( 'networkidle' );
// Check if the page has loaded successfully.
await expect( page.getByText( 'Active Filters block' ) ).toBeVisible();
@ -31,9 +33,11 @@ test.describe( 'Filter by Attributes Block - with All products Block', () => {
page,
} ) => {
await page.goto(
'/active-filters-block/?filter_color=blue,gray&query_type_color=or'
'/active-filters-block/?filter_color=blue,gray&query_type_color=or',
{
waitUntil: 'commit',
}
);
await page.waitForLoadState( 'networkidle' );
// Check if the page has loaded successfully.
await expect( page.getByText( 'Active Filters block' ) ).toBeVisible();
@ -54,9 +58,11 @@ test.describe( 'Filter by Attributes Block - with All products Block', () => {
page,
} ) => {
await page.goto(
'/active-filters-block/?filter_color=blue&query_type_color=or&min_price=15&max_price=40'
'/active-filters-block/?filter_color=blue&query_type_color=or&min_price=15&max_price=40',
{
waitUntil: 'commit',
}
);
await page.waitForLoadState( 'networkidle' );
// Check if the page has loaded successfully.
await expect( page.getByText( 'Active Filters block' ) ).toBeVisible();

View File

@ -11,7 +11,7 @@ test.describe(
'A basic set of tests to ensure WP, wp-admin and my-account load',
async () => {
test( 'Load the home page', async ( { page } ) => {
await page.goto( '/', { waitUntil: 'networkidle' } );
await page.goto( '/', { waitUntil: 'commit' } );
const title = page
.locator( 'header' )
.locator( '.wp-block-site-title' );
@ -22,7 +22,7 @@ test.describe(
test.describe( 'Sign in as admin', () => {
test( 'Load wp-admin', async ( { page } ) => {
await page.goto( '/wp-admin', { waitUntil: 'networkidle' } );
await page.goto( '/wp-admin', { waitUntil: 'commit' } );
const title = page.locator( 'div.wrap > h1' );
await expect( title ).toHaveText( 'Dashboard' );
} );
@ -33,7 +33,7 @@ test.describe(
storageState: process.env.CUSTOMERSTATE,
} );
test( 'Load customer my account page', async ( { page } ) => {
await page.goto( '/my-account', { waitUntil: 'networkidle' } );
await page.goto( '/my-account', { waitUntil: 'commit' } );
const title = page.locator( 'h1.wp-block-post-title' );
await expect( title ).toHaveText( 'My Account' );
} );

View File

@ -41,7 +41,7 @@ test.describe( 'Merchant → Cart', () => {
test( 'can only be inserted once', async ( { page, editorUtils } ) => {
await editorUtils.openGlobalBlockInserter();
await page.getByPlaceholder( 'Search' ).fill( blockData.slug );
const cartBlockButton = await page.locator( 'button', {
const cartBlockButton = page.locator( 'button', {
has: page.locator( `text="${ blockData.name }"` ),
} );
await expect( cartBlockButton ).toHaveAttribute(
@ -57,11 +57,11 @@ test.describe( 'Merchant → Cart', () => {
} ) => {
// Begin by removing the block.
await editor.selectBlocks( blockSelectorInEditor );
const options = await page
const options = page
.getByRole( 'toolbar', { name: 'Block tools' } )
.getByRole( 'button', { name: 'Options' } );
await options.click();
const removeButton = await page.getByText( 'Remove Cart' );
const removeButton = page.getByText( 'Remove Cart' );
await removeButton.click();
// Expect block to have been removed.
await expect(
@ -94,14 +94,14 @@ test.describe( 'Merchant → Cart', () => {
' [data-type="woocommerce/cart-order-summary-block"]'
);
const addBlockButton = await editor.canvas
const addBlockButton = editor.canvas
.getByRole( 'document', { name: 'Block: Order Summary' } )
.getByRole( 'button', { name: 'Add block' } );
await addBlockButton.dispatchEvent( 'click' );
await editor.page
.getByLabel( 'Search for blocks and patterns' )
.fill( 'Table' );
const tableButton = await editor.page.getByRole( 'option', {
const tableButton = editor.page.getByRole( 'option', {
name: 'Table',
} );
await expect( tableButton ).toBeVisible();
@ -110,7 +110,7 @@ test.describe( 'Merchant → Cart', () => {
.getByLabel( 'Search for blocks and patterns' )
.fill( 'Audio' );
const audioButton = await editor.page.getByRole( 'option', {
const audioButton = editor.page.getByRole( 'option', {
name: 'Audio',
} );
await test.expect( audioButton ).toBeVisible();
@ -120,26 +120,20 @@ test.describe( 'Merchant → Cart', () => {
blockSelectorInEditor +
' [data-type="woocommerce/filled-cart-block"]'
);
const filledCartAddBlockButton = await editor.canvas
const filledCartAddBlockButton = editor.canvas
.getByRole( 'document', { name: 'Block: Filled Cart' } )
.getByRole( 'button', { name: 'Add block' } )
.first();
await filledCartAddBlockButton.click();
const filledCartTableButton = await editor.page.getByRole(
'option',
{
name: 'Table',
}
);
const filledCartTableButton = editor.page.getByRole( 'option', {
name: 'Table',
} );
await expect( filledCartTableButton ).toBeVisible();
const filledCartAudioButton = await editor.page.getByRole(
'option',
{
name: 'Audio',
}
);
const filledCartAudioButton = editor.page.getByRole( 'option', {
name: 'Audio',
} );
await expect( filledCartAudioButton ).toBeHidden();
} );
@ -152,7 +146,7 @@ test.describe( 'Merchant → Cart', () => {
await editor.page
.getByRole( 'button', { name: 'Switch view' } )
.click();
const emptyCartButton = await page.getByRole( 'menuitem', {
const emptyCartButton = page.getByRole( 'menuitem', {
name: 'Empty Cart',
} );
@ -171,7 +165,7 @@ test.describe( 'Merchant → Cart', () => {
await editor.selectBlocks( blockSelectorInEditor );
await page.getByRole( 'button', { name: 'Switch view' } ).click();
const filledCartButton = await page.getByRole( 'menuitem', {
const filledCartButton = page.getByRole( 'menuitem', {
name: 'Filled Cart',
} );

View File

@ -81,7 +81,7 @@ for ( const { templateTitle, slug } of Object.values( templates ) ) {
// These tests consistently fail due to the default content of the page--potentially the classic block is not being
// used after another test runs. Reenable this when we have a solution for this.
// eslint-disable-next-line playwright/no-skipped-test
test.skip( `is rendered on ${ templateTitle } template - frontend side`, async ( {
admin,
editor,

View File

@ -19,10 +19,9 @@ const blockData = {
const publishAndVisitPost = async ( { page, editor } ) => {
await editor.publishPost();
await page.waitForLoadState( 'networkidle' );
const url = new URL( page.url() );
const postId = url.searchParams.get( 'post' );
await page.goto( `/?p=${ postId }`, { waitUntil: 'networkidle' } );
await page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
};
const selectTextOnlyOption = async ( { page } ) => {
@ -30,7 +29,7 @@ const selectTextOnlyOption = async ( { page } ) => {
.locator( blockData.selectors.editor.iconOptions )
.selectOption( 'Text-only' );
await page.locator( blockData.selectors.editor.iconToggle );
page.locator( blockData.selectors.editor.iconToggle );
};
const selectIconOnlyOption = async ( { page } ) => {
@ -38,7 +37,7 @@ const selectIconOnlyOption = async ( { page } ) => {
.locator( blockData.selectors.editor.iconOptions )
.selectOption( 'Icon-only' );
await page.locator( blockData.selectors.editor.iconToggle );
page.locator( blockData.selectors.editor.iconToggle );
};
const selectIconAndTextOption = async ( { page } ) => {
@ -46,7 +45,7 @@ const selectIconAndTextOption = async ( { page } ) => {
.locator( blockData.selectors.editor.iconOptions )
.selectOption( 'Icon and text' );
await page.locator( blockData.selectors.editor.iconToggle );
page.locator( blockData.selectors.editor.iconToggle );
};
test.describe( `${ blockData.name } Block`, () => {
@ -70,7 +69,7 @@ test.describe( `${ blockData.name } Block`, () => {
).toBeVisible();
await expect(
block.locator( blockData.selectors.frontend.icon )
).not.toBeVisible();
).toBeHidden();
} );
test( 'Icon Options can be set to Icon-only', async ( {
@ -90,7 +89,7 @@ test.describe( `${ blockData.name } Block`, () => {
await expect(
block.locator( blockData.selectors.frontend.label )
).not.toBeVisible();
).toBeHidden();
await expect(
block.locator( blockData.selectors.frontend.icon )
).toBeVisible();

View File

@ -17,7 +17,7 @@ const blockData: BlockData = {
};
const getMiniCartButton = async ( { page } ) => {
return await page.getByLabel( '0 items in cart, total price of $0.00' );
return page.getByLabel( '0 items in cart, total price of $0.00' );
};
test.describe( `${ blockData.name } Block`, () => {
@ -26,10 +26,9 @@ test.describe( `${ blockData.name } Block`, () => {
await admin.createNewPost();
await editor.insertBlock( { name: blockData.name } );
await editor.publishPost();
await page.waitForLoadState( 'networkidle' );
const url = new URL( page.url() );
const postId = url.searchParams.get( 'post' );
await page.goto( `/?p=${ postId }`, { waitUntil: 'networkidle' } );
await page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
} );
test( 'should open the empty cart drawer', async ( { page } ) => {
@ -58,7 +57,7 @@ test.describe( `${ blockData.name } Block`, () => {
blockData.selectors.frontend.drawerCloseButton
);
const closeButton = await page.$(
const closeButton = page.locator(
blockData.selectors.frontend.drawerCloseButton
);
@ -113,16 +112,14 @@ test.describe( `${ blockData.name } Block`, () => {
await editor.insertBlock( { name: blockData.name } );
await editor.insertBlock( { name: 'woocommerce/all-products' } );
await editor.publishPost();
await page.waitForLoadState( 'networkidle' );
const url = new URL( page.url() );
const postId = url.searchParams.get( 'post' );
await page.goto( `/?p=${ postId }`, { waitUntil: 'networkidle' } );
await page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
} );
test( 'should open the filled cart drawer', async ( { page } ) => {
const miniCartButton = await getMiniCartButton( { page } );
await page.waitForLoadState( 'networkidle' );
await page.click( 'text=Add to cart' );
await miniCartButton.click();

View File

@ -57,16 +57,15 @@ test.describe(
} );
cartInput.fill( 'updated-cart-permalink' );
await page.click( 'button[name="save"]' );
await page.waitForLoadState( 'networkidle' );
// Visit the updated page.
await page.goto( '/updated-cart-permalink', {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
const cartText = await page.getByRole( 'link', {
const cartText = page.getByRole( 'link', {
name: 'Proceed to Checkout',
} );
expect( cartText ).toBeVisible();
await expect( cartText ).toBeVisible();
} );
test( 'Changing checkout permalink works', async ( { page } ) => {
@ -78,14 +77,14 @@ test.describe(
} );
checkoutInput.fill( 'updated-checkout-permalink' );
await page.click( 'button[name="save"]' );
await page.waitForLoadState( 'networkidle' );
await page.waitForLoadState( 'commit' );
// Visit the updated page.
await page.goto( '/updated-checkout-permalink', {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
const cartText = await page.getByText( 'Place Order' );
expect( cartText ).toBeVisible();
const cartText = page.getByText( 'Place Order' );
await expect( cartText ).toBeVisible();
} );
} );
}

View File

@ -38,20 +38,17 @@ test.describe( `${ blockData.name } Block - with All products Block`, () => {
},
} );
await editor.publishPost();
await page.waitForLoadState( 'networkidle' );
const url = new URL( page.url() );
const postId = url.searchParams.get( 'post' );
await page.goto( `/?p=${ postId }`, { waitUntil: 'networkidle' } );
await page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
} );
test( 'should show all products', async ( { page, frontendUtils } ) => {
test( 'should show all products', async ( { frontendUtils } ) => {
const allProductsBlock = await frontendUtils.getBlockByName(
'woocommerce/all-products'
);
await page.waitForLoadState( 'networkidle' );
const img = await allProductsBlock.locator( 'img' ).first();
const img = allProductsBlock.locator( 'img' ).first();
await expect( img ).not.toHaveAttribute(
'src',
@ -82,14 +79,11 @@ test.describe( `${ blockData.name } Block - with All products Block`, () => {
response.url().includes( blockData.endpointAPI )
);
await page.waitForLoadState( 'networkidle' );
const allProductsBlock = await frontendUtils.getBlockByName(
'woocommerce/all-products'
);
await page.waitForLoadState( 'networkidle' );
const img = await allProductsBlock.locator( 'img' ).first();
const img = allProductsBlock.locator( 'img' ).first();
await expect( img ).not.toHaveAttribute(
'src',
@ -127,7 +121,7 @@ test.describe( `${ blockData.name } Block - with PHP classic template`, () => {
},
} );
await editor.saveSiteEditorEntities();
await page.goto( `/shop`, { waitUntil: 'networkidle' } );
await page.goto( `/shop`, { waitUntil: 'commit' } );
} );
test.afterEach( async ( { templateApiUtils } ) => {
@ -136,13 +130,11 @@ test.describe( `${ blockData.name } Block - with PHP classic template`, () => {
);
} );
test( 'should show all products', async ( { page, frontendUtils } ) => {
test( 'should show all products', async ( { frontendUtils } ) => {
const legacyTemplate = await frontendUtils.getBlockByName(
'woocommerce/legacy-template'
);
await page.waitForLoadState( 'networkidle' );
const products = await legacyTemplate
.getByRole( 'list' )
.locator( '.product' )
@ -151,6 +143,7 @@ test.describe( `${ blockData.name } Block - with PHP classic template`, () => {
expect( products ).toHaveLength( 16 );
} );
// eslint-disable-next-line playwright/no-skipped-test
test.skip( 'should show only products that match the filter', async ( {
page,
pageUtils,

View File

@ -6,11 +6,11 @@ import { Locator } from '@playwright/test';
export const getMinMaxPriceInputs = async (
priceFilterBlockLocator: Locator
) => {
const maxPriceInput = await priceFilterBlockLocator.locator(
const maxPriceInput = priceFilterBlockLocator.locator(
'.wc-block-price-filter__amount--max'
);
const minPriceInput = await priceFilterBlockLocator.locator(
const minPriceInput = priceFilterBlockLocator.locator(
'.wc-block-price-filter__amount--min'
);

View File

@ -26,20 +26,20 @@ test.describe( 'Product Collection', () => {
pageObject,
} ) => {
expect( pageObject.productTemplate ).not.toBeNull();
expect( pageObject.products ).toHaveCount( 9 );
expect( pageObject.productImages ).toHaveCount( 9 );
expect( pageObject.productTitles ).toHaveCount( 9 );
expect( pageObject.productPrices ).toHaveCount( 9 );
expect( pageObject.addToCartButtons ).toHaveCount( 9 );
await expect( pageObject.products ).toHaveCount( 9 );
await expect( pageObject.productImages ).toHaveCount( 9 );
await expect( pageObject.productTitles ).toHaveCount( 9 );
await expect( pageObject.productPrices ).toHaveCount( 9 );
await expect( pageObject.addToCartButtons ).toHaveCount( 9 );
await pageObject.publishAndGoToFrontend();
expect( pageObject.productTemplate ).not.toBeNull();
expect( pageObject.products ).toHaveCount( 9 );
expect( pageObject.productImages ).toHaveCount( 9 );
expect( pageObject.productTitles ).toHaveCount( 9 );
expect( pageObject.productPrices ).toHaveCount( 9 );
expect( pageObject.addToCartButtons ).toHaveCount( 9 );
await expect( pageObject.products ).toHaveCount( 9 );
await expect( pageObject.productImages ).toHaveCount( 9 );
await expect( pageObject.productTitles ).toHaveCount( 9 );
await expect( pageObject.productPrices ).toHaveCount( 9 );
await expect( pageObject.addToCartButtons ).toHaveCount( 9 );
} );
test.describe( 'Product Collection Sidebar Settings', () => {
@ -200,6 +200,7 @@ test.describe( 'Product Collection', () => {
} );
// TODO There are no products with stock status 'Out of stock' in test data.
// eslint-disable-next-line playwright/no-skipped-test
test.skip( 'Products can be filtered based on stock status (in stock, out of stock, or backorder).', async ( {
pageObject,
} ) => {
@ -226,7 +227,7 @@ test.describe( 'Product Collection', () => {
sidebarSettings.locator(
SELECTORS.inheritQueryFromTemplateControl
)
).not.toBeVisible();
).toBeHidden();
} );
test( 'Inherit query from template should work as expected in Product Catalog template', async ( {
@ -293,18 +294,18 @@ test.describe( 'Product Collection', () => {
maxPageToShow: 2,
} );
expect( await pageObject.products ).toHaveCount( 3 );
await expect( await pageObject.products ).toHaveCount( 3 );
await pageObject.setDisplaySettings( {
itemsPerPage: 2,
offset: 0,
maxPageToShow: 2,
} );
expect( await pageObject.products ).toHaveCount( 2 );
await expect( await pageObject.products ).toHaveCount( 2 );
await pageObject.publishAndGoToFrontend();
expect( await pageObject.products ).toHaveCount( 2 );
await expect( await pageObject.products ).toHaveCount( 2 );
const paginationNumbers =
pageObject.pagination.locator( '.page-numbers' );
@ -322,9 +323,7 @@ test.describe( 'Product Collection', () => {
// In the original viewport size, we expect the product width to be less than the parent width
// because we will have more than 1 column
let productSize = await firstProduct.boundingBox();
let parentSize = await (
await firstProduct.locator( 'xpath=..' )
).boundingBox();
let parentSize = await firstProduct.locator( 'xpath=..' ).boundingBox();
expect( productSize?.width ).toBeLessThan(
parentSize?.width as number
);
@ -337,9 +336,7 @@ test.describe( 'Product Collection', () => {
// In the smaller viewport size, we expect the product width to be (approximately) the same as the parent width
// because we will have only 1 column
productSize = await firstProduct.boundingBox();
parentSize = await (
await firstProduct.locator( 'xpath=..' )
).boundingBox();
parentSize = await firstProduct.locator( 'xpath=..' ).boundingBox();
expect( productSize?.width ).toBeCloseTo( parentSize?.width as number );
} );
} );

View File

@ -73,7 +73,7 @@ class ProductCollectionPage {
await this.editor.publishPost();
const url = new URL( this.page.url() );
const postId = url.searchParams.get( 'post' );
await this.page.goto( `/?p=${ postId }`, { waitUntil: 'networkidle' } );
await this.page.goto( `/?p=${ postId }`, { waitUntil: 'commit' } );
await this.refreshLocators( 'frontend' );
}
@ -105,6 +105,8 @@ class ProductCollectionPage {
await this.page
.getByRole( 'button', { name: 'Filters options' } )
.click();
// We should refactor this code. We should not wait for timeout.
// eslint-disable-next-line playwright/no-wait-for-timeout
await this.page.waitForTimeout( 500 );
await this.page
.getByRole( 'menuitemcheckbox', {
@ -118,7 +120,7 @@ class ProductCollectionPage {
async setNumberOfColumns( numberOfColumns: number ) {
const sidebarSettings = await this.locateSidebarSettings();
const inputField = await sidebarSettings.getByRole( 'spinbutton', {
const inputField = sidebarSettings.getByRole( 'spinbutton', {
name: 'Columns',
} );
await inputField.fill( numberOfColumns.toString() );
@ -134,7 +136,7 @@ class ProductCollectionPage {
| 'rating/desc'
) {
const sidebarSettings = await this.locateSidebarSettings();
const orderByComboBox = await sidebarSettings.getByRole( 'combobox', {
const orderByComboBox = sidebarSettings.getByRole( 'combobox', {
name: 'Order by',
} );
await orderByComboBox.selectOption( orderBy );
@ -201,6 +203,7 @@ class ProductCollectionPage {
await input.clear();
await input.fill( keyword );
// Timeout is needed because of debounce in the block.
// eslint-disable-next-line playwright/no-wait-for-timeout
await this.page.waitForTimeout( 300 );
await this.refreshLocators( 'editor' );
}
@ -227,7 +230,7 @@ class ProductCollectionPage {
.click();
// Set the values.
const displaySettingsContainer = await this.page.locator(
const displaySettingsContainer = this.page.locator(
'.wc-block-editor-product-collection__display-settings'
);
await displaySettingsContainer.getByLabel( 'Items per Page' ).click();
@ -248,10 +251,9 @@ class ProductCollectionPage {
}
async setProductAttribute( attribute: 'Color' | 'Size', value: string ) {
await this.page.waitForLoadState( 'networkidle' );
const sidebarSettings = await this.locateSidebarSettings();
const productAttributesContainer = await sidebarSettings.locator(
const productAttributesContainer = sidebarSettings.locator(
'.woocommerce-product-attributes'
);
@ -303,7 +305,7 @@ class ProductCollectionPage {
* Locators
*/
async locateSidebarSettings() {
return await this.page.getByRole( 'region', {
return this.page.getByRole( 'region', {
name: 'Editor settings',
} );
}
@ -322,58 +324,50 @@ class ProductCollectionPage {
}
private async initializeLocatorsForEditor() {
this.productTemplate = await this.page.locator(
SELECTORS.productTemplate
);
this.products = await this.page
this.productTemplate = this.page.locator( SELECTORS.productTemplate );
this.products = this.page
.locator( SELECTORS.product )
.locator( 'visible=true' );
this.productImages = await this.page
this.productImages = this.page
.locator( SELECTORS.productImage.inEditor )
.locator( 'visible=true' );
this.productTitles = await this.productTemplate
this.productTitles = this.productTemplate
.locator( SELECTORS.productTitle )
.locator( 'visible=true' );
this.productPrices = await this.page
this.productPrices = this.page
.locator( SELECTORS.productPrice.inEditor )
.locator( 'visible=true' );
this.addToCartButtons = await this.page
this.addToCartButtons = this.page
.locator( SELECTORS.addToCartButton.inEditor )
.locator( 'visible=true' );
this.pagination = await this.page.getByRole( 'document', {
this.pagination = this.page.getByRole( 'document', {
name: 'Block: Pagination',
} );
}
private async initializeLocatorsForFrontend() {
this.productTemplate = await this.page.locator(
SELECTORS.productTemplate
);
this.products = await this.page.locator( SELECTORS.product );
this.productImages = await this.productTemplate.locator(
this.productTemplate = this.page.locator( SELECTORS.productTemplate );
this.products = this.page.locator( SELECTORS.product );
this.productImages = this.productTemplate.locator(
SELECTORS.productImage.onFrontend
);
this.productTitles = await this.productTemplate.locator(
this.productTitles = this.productTemplate.locator(
SELECTORS.productTitle
);
this.productPrices = await this.productTemplate.locator(
this.productPrices = this.productTemplate.locator(
SELECTORS.productPrice.onFrontend
);
this.addToCartButtons = await this.productTemplate.locator(
this.addToCartButtons = this.productTemplate.locator(
SELECTORS.addToCartButton.onFrontend
);
this.pagination = await this.page.locator(
SELECTORS.pagination.onFrontend
);
this.pagination = this.page.locator( SELECTORS.pagination.onFrontend );
}
private async waitForProductsToLoad() {
await this.page.waitForLoadState( 'networkidle' );
// Wait for the product blocks to be loaded.
await this.page.waitForSelector( SELECTORS.product );
// Wait for the loading spinner to be detached.
await this.page.waitForSelector( '.is-loading', { state: 'detached' } );
await this.page.waitForLoadState( 'networkidle' );
}
}

View File

@ -58,7 +58,7 @@ test.describe( `${ blockData.name }`, () => {
] );
await page.goto( blockData.productPage, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
const blockFrontend = await frontendUtils.getBlockByName(
@ -93,7 +93,7 @@ test.describe( `${ blockData.name }`, () => {
await editor.saveSiteEditorEntities();
await page.goto( blockData.productPage, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
} );
@ -111,8 +111,10 @@ test.describe( `${ blockData.name }`, () => {
'woocommerce/product-image-gallery'
);
const clientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await parentBlock.getAttribute( 'data-block' ) ) ?? '';
const parentClientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await editorUtils.getBlockRootClientId( clientId ) ) ?? '';
await editor.selectBlocks( parentBlock );
@ -132,6 +134,8 @@ test.describe( `${ blockData.name }`, () => {
)
.click();
// We should refactor this.
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout( 500 );
const groupBlock = await editorUtils.getBlockByTypeWithParent(
@ -162,7 +166,7 @@ test.describe( `${ blockData.name }`, () => {
] );
await page.goto( blockData.productPage, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
const groupBlockFrontend =
@ -202,8 +206,10 @@ test.describe( `${ blockData.name }`, () => {
'woocommerce/product-image-gallery'
);
const clientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await parentBlock.getAttribute( 'data-block' ) ) ?? '';
const parentClientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await editorUtils.getBlockRootClientId( clientId ) ) ?? '';
await editor.selectBlocks( parentBlock );
@ -223,6 +229,8 @@ test.describe( `${ blockData.name }`, () => {
)
.click();
// We should refactor this.
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout( 500 );
const groupBlock = await editorUtils.getBlockByTypeWithParent(
@ -253,7 +261,7 @@ test.describe( `${ blockData.name }`, () => {
] );
await page.goto( blockData.productPage, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
const groupBlockFrontend =
@ -295,8 +303,10 @@ test.describe( `${ blockData.name }`, () => {
'woocommerce/product-image-gallery'
);
const clientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await parentBlock.getAttribute( 'data-block' ) ) ?? '';
const parentClientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await editorUtils.getBlockRootClientId( clientId ) ) ?? '';
await editor.selectBlocks( parentBlock );
@ -316,6 +326,8 @@ test.describe( `${ blockData.name }`, () => {
)
.click();
// We should refactor this.
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout( 500 );
const groupBlock = await editorUtils.getBlockByTypeWithParent(
@ -346,7 +358,7 @@ test.describe( `${ blockData.name }`, () => {
] );
await page.goto( blockData.productPage, {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
const groupBlockFrontend =

View File

@ -74,14 +74,14 @@ test.describe( `${ blockData.name } Block `, () => {
await editor.openDocumentSettingsSidebar();
const advancedFilterOption = await page.getByLabel(
const advancedFilterOption = page.getByLabel(
'Advanced Filters options'
);
const inheritQueryFromTemplateOption = await page.getByLabel(
const inheritQueryFromTemplateOption = page.getByLabel(
'Inherit query from template'
);
await expect( advancedFilterOption ).not.toBeVisible();
await expect( advancedFilterOption ).toBeHidden();
await expect( inheritQueryFromTemplateOption ).toBeVisible();
} );
test( 'when Inherit Query from template is disabled all the settings that customize the query should be visble', async ( {
@ -102,10 +102,10 @@ test.describe( `${ blockData.name } Block `, () => {
await editor.openDocumentSettingsSidebar();
const advancedFilterOption = await page.getByLabel(
const advancedFilterOption = page.getByLabel(
'Advanced Filters options'
);
const inheritQueryFromTemplateOption = await page.getByLabel(
const inheritQueryFromTemplateOption = page.getByLabel(
'Inherit query from template'
);
@ -139,10 +139,11 @@ for ( const {
} );
await editor.canvas.click( 'body' );
await editor.canvas.waitForLoadState( 'networkidle' );
const block = await editorUtils.getBlockByName( blockData.name );
// eslint-disable-next-line playwright/no-conditional-in-test
const clientId = ( await block.getAttribute( 'data-block' ) ) ?? '';
const parentClientId =
// eslint-disable-next-line playwright/no-conditional-in-test
( await editorUtils.getBlockRootClientId( clientId ) ) ?? '';
await editor.selectBlocks( block );
await editorUtils.insertBlock(

View File

@ -4,13 +4,11 @@
import { Page } from '@playwright/test';
export const getProductsNameFromClassicTemplate = async ( page: Page ) => {
const products = await page.locator( '.woocommerce-loop-product__title' );
const products = page.locator( '.woocommerce-loop-product__title' );
return products.allTextContents();
};
export const getProductsNameFromProductQuery = async ( page: Page ) => {
const products = await page.locator(
'.wp-block-query .wp-block-post-title'
);
const products = page.locator( '.wp-block-query .wp-block-post-title' );
return products.allTextContents();
};

View File

@ -46,7 +46,7 @@ for ( const { classes, product, frontendPage } of products ) {
page,
} ) => {
await page.goto( frontendPage );
const body = await page.locator( 'body' );
const body = page.locator( 'body' );
const bodyClasses = await body.getAttribute( 'class' );
classes.forEach( ( className ) => {

View File

@ -52,7 +52,7 @@ test.describe( 'Test the cart template', async () => {
await editor.page.waitForResponse( ( response ) =>
response.url().includes( permalink )
);
await page.goto( permalink, { waitUntil: 'networkidle' } );
await page.goto( permalink, { waitUntil: 'commit' } );
await expect( page.getByText( 'Hello World' ).first() ).toBeVisible();
} );

View File

@ -39,7 +39,7 @@ test.describe( 'Test the checkout header template part', async () => {
} );
await editor.saveSiteEditorEntities();
await page.goto( permalink, { waitUntil: 'networkidle' } );
await page.goto( permalink, { waitUntil: 'commit' } );
await expect( page.getByText( 'Hello World' ).first() ).toBeVisible();
} );

View File

@ -46,7 +46,7 @@ test.describe( 'Test the checkout template', async () => {
attributes: { content: 'Hello World' },
} );
await editor.saveSiteEditorEntities();
await page.goto( permalink, { waitUntil: 'networkidle' } );
await page.goto( permalink, { waitUntil: 'commit' } );
await expect( page.getByText( 'Hello World' ).first() ).toBeVisible();
} );

View File

@ -8,6 +8,7 @@ const templatePath = 'woocommerce/woocommerce//order-confirmation';
const templateType = 'wp_template';
test.fixme( 'Test the order confirmation template', async () => {
// eslint-disable-next-line playwright/expect-expect
test( 'Template can be opened in the site editor', async ( {
page,
editorUtils,
@ -45,7 +46,7 @@ test.fixme( 'Test the order confirmation template', async () => {
attributes: { content: 'Hello World' },
} );
await editor.saveSiteEditorEntities();
await page.goto( permalink, { waitUntil: 'networkidle' } );
await page.goto( permalink, { waitUntil: 'commit' } );
await expect( page.getByText( 'Hello World' ).first() ).toBeVisible();
} );

View File

@ -22,7 +22,7 @@ export class EditorUtils {
if ( ! parentBlock ) {
throw new Error( `Parent block "${ parentName }" not found.` );
}
const block = await parentBlock.locator( `[data-type="${ name }"]` );
const block = parentBlock.locator( `[data-type="${ name }"]` );
return block;
}

View File

@ -23,18 +23,17 @@ export class FrontendUtils {
if ( ! parentBlock ) {
throw new Error( `Parent block "${ parentName }" not found.` );
}
const block = await parentBlock.locator( `.${ blockClass }` );
const block = parentBlock.locator( `.${ blockClass }` );
return block;
}
async addToCart() {
await this.page.click( 'text=Add to cart' );
await this.page.waitForLoadState( 'networkidle' );
}
async goToShop() {
await this.page.goto( '/shop', {
waitUntil: 'networkidle',
waitUntil: 'commit',
} );
}

View File

@ -10,7 +10,7 @@ import { BlockData } from '@woocommerce/e2e-types';
export const closeModalIfExists = async ( page: Page ) => {
// The modal close button can have different aria-labels, depending on the version of Gutenberg/WP.
// Newer versions (WP >=6.2) use `Close`, while older versions (WP <6.1) use `Close dialog`.
const closeButton = await page.getByLabel( /^Close$|^Close dialog$/ );
const closeButton = page.getByLabel( /^Close$|^Close dialog$/ );
if ( ( await closeButton.count() ) > 0 ) {
await closeButton.click();
}
@ -35,7 +35,6 @@ export const editBlockPage = async (
.getByRole( 'link', { name: `${ name } block” (Edit)` } )
.click();
await page.waitForLoadState( 'networkidle' );
await page.waitForSelector( blockSelector );
await closeModalIfExists( page );
};