diff --git a/plugins/woocommerce/.eslintignore b/plugins/woocommerce/.eslintignore index dfd656285db..4332c035a10 100644 --- a/plugins/woocommerce/.eslintignore +++ b/plugins/woocommerce/.eslintignore @@ -1,20 +1,27 @@ *.min.js -/assets/js/accounting/** -/assets/js/flexslider/** -/assets/js/jquery-blockui/** -/assets/js/jquery-cookie/** -/assets/js/jquery-flot/** -/assets/js/jquery-payment/** -/assets/js/jquery-qrcode/** -/assets/js/jquery-serializejson/** -/assets/js/jquery-tiptip/** -/assets/js/jquery-ui-touch-punch/** -/assets/js/js-cookie/** -/assets/js/photoswipe/** -/assets/js/prettyPhoto/** -/assets/js/round/** -/assets/js/select2/** -/assets/js/selectWoo/** -/assets/js/stupidtable/** -/assets/js/zoom/** \ No newline at end of file +/.wireit/** +/assets/** +/bin/composer/** +/client/legacy/build/** +/client/legacy/js/accounting/** +/client/legacy/js/flexslider/** +/client/legacy/js/jquery-blockui/** +/client/legacy/js/jquery-cookie/** +/client/legacy/js/jquery-flot/** +/client/legacy/js/jquery-payment/** +/client/legacy/js/jquery-qrcode/** +/client/legacy/js/jquery-serializejson/** +/client/legacy/js/jquery-tiptip/** +/client/legacy/js/jquery-ui-touch-punch/** +/client/legacy/js/js-cookie/** +/client/legacy/js/photoswipe/** +/client/legacy/js/prettyPhoto/** +/client/legacy/js/round/** +/client/legacy/js/select2/** +/client/legacy/js/selectWoo/** +/client/legacy/js/stupidtable/** +/client/legacy/js/zoom/** +/includes/gateways/** +/tests/e2e/** +/vendor/** diff --git a/plugins/woocommerce/.eslintrc.js b/plugins/woocommerce/.eslintrc.js index a5b4e437b5f..63bb844f745 100644 --- a/plugins/woocommerce/.eslintrc.js +++ b/plugins/woocommerce/.eslintrc.js @@ -1,5 +1,3 @@ -/** @format */ - module.exports = { env: { browser: true, diff --git a/plugins/woocommerce/bin/eslint-branch.sh b/plugins/woocommerce/bin/eslint-branch.sh new file mode 100644 index 00000000000..fdde2f2d27e --- /dev/null +++ b/plugins/woocommerce/bin/eslint-branch.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Lint branch +# +# Runs eslint, comparing the current branch to its "base" or "parent" branch. +# The base branch defaults to trunk, but another branch name can be specified as an +# optional positional argument. +# +# Example: +# ./eslint-branch.sh base-branch + +baseBranch=${1:-"trunk"} + +# shellcheck disable=SC2046 +changedFiles=$(git diff $(git merge-base HEAD $baseBranch) --relative --name-only --diff-filter=d -- '*.js' '*ts' '*tsx') + +# Only complete this if changed files are detected. +if [[ -z $changedFiles ]]; then + echo "No changed files detected." + exit 0 +fi + +# shellcheck disable=SC2086 +pnpm eslint $changedFiles diff --git a/plugins/woocommerce/bin/package-update-textdomain.js b/plugins/woocommerce/bin/package-update-textdomain.js index 0cc5fc65d4e..d24c801f63f 100755 --- a/plugins/woocommerce/bin/package-update-textdomain.js +++ b/plugins/woocommerce/bin/package-update-textdomain.js @@ -20,6 +20,6 @@ wpTextdomain( 'packages/**/*.php', { '_nx:1,2,4c,5d', '_n_noop:1,2,3d', '_nx_noop:1,2,3c,4d', - 'wp_set_script_translations:1,2d,3' + 'wp_set_script_translations:1,2d,3', ], } ); diff --git a/plugins/woocommerce/changelog/tools-add-js-lint-in-woocommerce-plugin b/plugins/woocommerce/changelog/tools-add-js-lint-in-woocommerce-plugin new file mode 100644 index 00000000000..560099a3bdc --- /dev/null +++ b/plugins/woocommerce/changelog/tools-add-js-lint-in-woocommerce-plugin @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Adds JS linting scripts for woocommerce plugin diff --git a/plugins/woocommerce/client/legacy/.eslintrc.js b/plugins/woocommerce/client/legacy/.eslintrc.js index a895d4dfc86..d4560a76ca5 100644 --- a/plugins/woocommerce/client/legacy/.eslintrc.js +++ b/plugins/woocommerce/client/legacy/.eslintrc.js @@ -17,7 +17,6 @@ module.exports = { 'max-len': [ 2, { 'code': 140 } ], 'no-console': 1 }, - parser: 'babel-eslint', parserOptions: { ecmaVersion: 8, ecmaFeatures: { diff --git a/plugins/woocommerce/package.json b/plugins/woocommerce/package.json index 8bc9fbb9438..771c5d0d6a7 100644 --- a/plugins/woocommerce/package.json +++ b/plugins/woocommerce/package.json @@ -35,8 +35,12 @@ "preinstall": "npx only-allow pnpm", "postinstall": "composer install", "lint": "pnpm --if-present '/^lint:lang:.*$/'", + "lint:changes:branch": "pnpm '/^lint:changes:branch:.*$/'", "lint:fix": "pnpm --if-present '/^lint:fix:lang:.*$/'", "lint:fix:lang:php": "composer run-script phpcbf", + "lint:changes:branch:js": "bash ./bin/eslint-branch.sh", + "lint:changes:branch:php": "pnpm lint:php:changes:branch", + "lint:lang:js": "eslint . --ext=js,ts", "lint:lang:php": "composer run-script phpcs", "lint:php": "composer run-script phpcs", "lint:php:changes": "composer run-script lint", @@ -80,7 +84,7 @@ "build_step": "pnpm build:zip", "ci": { "lint": { - "command": "lint:php:changes:branch ", + "command": "lint:changes:branch ", "changes": [ "composer.lock", "includes/**/*.php", @@ -89,7 +93,8 @@ "templates/**/*.php", "tests/php/**/*.php", "tests/legacy/unit-tests/**/*.php", - "tests/unit-tests/**/*.php" + "tests/unit-tests/**/*.php", + "tests/**/*.js" ] }, "tests": [ diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js index 8e0940ff338..23b90612ced 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-edit.spec.js @@ -1,184 +1,177 @@ const { test: baseTest, expect } = require( '../../fixtures/fixtures' ); -baseTest.describe( 'Products > Edit Product', () => { - const test = baseTest.extend( { - storageState: process.env.ADMINSTATE, - products: async ( { api }, use ) => { - const products = []; +const test = baseTest.extend( { + storageState: process.env.ADMINSTATE, + products: async ( { api }, use ) => { + const products = []; - for ( let i = 0; i < 2; i++ ) { - await api - .post( 'products', { - id: 0, - name: `Product ${ i }_${ Date.now() }`, - type: 'simple', - regular_price: `${ 12.99 + i }`, - manage_stock: true, - stock_quantity: 10 + i, - stock_status: 'instock', - } ) - .then( ( response ) => { - products.push( response.data ); - } ); - } + for ( let i = 0; i < 2; i++ ) { + await api + .post( 'products', { + id: 0, + name: `Product ${ i }_${ Date.now() }`, + type: 'simple', + regular_price: `${ 12.99 + i }`, + manage_stock: true, + stock_quantity: 10 + i, + stock_status: 'instock', + } ) + .then( ( response ) => { + products.push( response.data ); + } ); + } - await use( products ); + await use( products ); - // Cleanup - for ( const product of products ) { - await api.delete( `products/${ product.id }`, { force: true } ); - } - }, + // Cleanup + for ( const product of products ) { + await api.delete( `products/${ product.id }`, { force: true } ); + } + }, +} ); + +test( 'can edit a product and save the changes', async ( { + page, + products, +} ) => { + await page.goto( + `wp-admin/post.php?post=${ products[ 0 ].id }&action=edit` + ); + + const newProduct = { + name: `Product ${ Date.now() }`, + description: `This product is pretty awesome ${ Date.now() }`, + regularPrice: '100.05', + salePrice: '99.05', + }; + + await test.step( 'edit the product name', async () => { + await page.getByLabel( 'Product name' ).fill( newProduct.name ); } ); - test( 'can edit a product and save the changes', async ( { - page, - products, - } ) => { - await page.goto( - `wp-admin/post.php?post=${ products[ 0 ].id }&action=edit` + await test.step( 'edit the product description', async () => { + await page.locator( '#content-html' ).click(); // text mode to work around iframe + await page + .locator( '.wp-editor-area' ) + .first() + .fill( newProduct.description ); + } ); + + await test.step( 'edit the product price', async () => { + await page + .getByLabel( 'Regular price ($)' ) + .fill( newProduct.regularPrice ); + await page.getByLabel( 'Sale price ($)' ).fill( newProduct.salePrice ); + } ); + + await test.step( 'publish the updated product', async () => { + await page.getByRole( 'button', { name: 'Update' } ).click(); + } ); + + await test.step( 'verify the changes', async () => { + await expect( page.getByLabel( 'Product name' ) ).toHaveValue( + newProduct.name + ); + await expect( page.locator( '.wp-editor-area' ).first() ).toContainText( + newProduct.description + ); + await expect( page.getByLabel( 'Regular price ($)' ) ).toHaveValue( + newProduct.regularPrice + ); + await expect( page.getByLabel( 'Sale price ($)' ) ).toHaveValue( + newProduct.salePrice ); - - const newProduct = { - name: `Product ${ Date.now() }`, - description: `This product is pretty awesome ${ Date.now() }`, - regularPrice: '100.05', - salePrice: '99.05', - }; - - await test.step( 'edit the product name', async () => { - await page.getByLabel( 'Product name' ).fill( newProduct.name ); - } ); - - await test.step( 'edit the product description', async () => { - await page.locator( '#content-html' ).click(); // text mode to work around iframe - await page - .locator( '.wp-editor-area' ) - .first() - .fill( newProduct.description ); - } ); - - await test.step( 'edit the product price', async () => { - await page - .getByLabel( 'Regular price ($)' ) - .fill( newProduct.regularPrice ); - await page - .getByLabel( 'Sale price ($)' ) - .fill( newProduct.salePrice ); - } ); - - await test.step( 'publish the updated product', async () => { - await page.getByRole( 'button', { name: 'Update' } ).click(); - } ); - - await test.step( 'verify the changes', async () => { - await expect( page.getByLabel( 'Product name' ) ).toHaveValue( - newProduct.name - ); - await expect( - page.locator( '.wp-editor-area' ).first() - ).toContainText( newProduct.description ); - await expect( page.getByLabel( 'Regular price ($)' ) ).toHaveValue( - newProduct.regularPrice - ); - await expect( page.getByLabel( 'Sale price ($)' ) ).toHaveValue( - newProduct.salePrice - ); - } ); - } ); - - test( 'can bulk edit products', async ( { page, products } ) => { - await page.goto( `wp-admin/edit.php?post_type=product` ); - - const regularPriceIncrease = 10; - const salePriceDecrease = 10; - const stockQtyIncrease = 10; - - await test.step( 'select and bulk edit the products', async () => { - for ( const product of products ) { - await page.getByLabel( `Select ${ product.name }` ).click(); - } - - await page - .locator( '#bulk-action-selector-top' ) - .selectOption( 'Edit' ); - await page.locator( '#doaction' ).click(); - - await expect( - await page.locator( '#bulk-titles-list li' ).count() - ).toEqual( products.length ); - } ); - - await test.step( 'update the regular price', async () => { - await page - .locator( 'select[name="change_regular_price"]' ) - .selectOption( - 'Increase existing price by (fixed amount or %):' - ); - await page - .getByPlaceholder( 'Enter price ($)' ) - .fill( `${ regularPriceIncrease }%` ); - } ); - - await test.step( 'update the sale price', async () => { - await page - .locator( 'select[name="change_sale_price"]' ) - .selectOption( - 'Set to regular price decreased by (fixed amount or %):' - ); - await page - .getByPlaceholder( 'Enter sale price ($)' ) - .fill( `${ salePriceDecrease }%` ); - } ); - - await test.step( 'update the stock quantity', async () => { - await page - .locator( 'select[name="change_stock"]' ) - .selectOption( 'Increase existing stock by:' ); - await page - .getByPlaceholder( 'Stock qty' ) - .fill( `${ stockQtyIncrease }` ); - } ); - - await test.step( 'save the updates', async () => { - await page.getByRole( 'button', { name: 'Update' } ).click(); - } ); - - await test.step( 'verify the changes', async () => { - for ( const product of products ) { - await page.goto( `product/${ product.slug }` ); - - const expectedRegularPrice = ( - product.regular_price * - ( 1 + regularPriceIncrease / 100 ) - ).toFixed( 2 ); - const expectedSalePrice = ( - expectedRegularPrice * - ( 1 - salePriceDecrease / 100 ) - ).toFixed( 2 ); - const expectedStockQty = - product.stock_quantity + stockQtyIncrease; - - await expect - .soft( - await page - .locator( 'del' ) - .getByText( `$${ expectedRegularPrice }` ) - .count() - ) - .toBeGreaterThan( 0 ); - await expect - .soft( - await page - .locator( 'ins' ) - .getByText( `$${ expectedSalePrice }` ) - .count() - ) - .toBeGreaterThan( 0 ); - await expect - .soft( page.getByText( `${ expectedStockQty } in stock` ) ) - .toBeVisible(); - } - } ); + } ); +} ); + +test( 'can bulk edit products', async ( { page, products } ) => { + await page.goto( `wp-admin/edit.php?post_type=product` ); + + const regularPriceIncrease = 10; + const salePriceDecrease = 10; + const stockQtyIncrease = 10; + + await test.step( 'select and bulk edit the products', async () => { + for ( const product of products ) { + await page.getByLabel( `Select ${ product.name }` ).click(); + } + + await page + .locator( '#bulk-action-selector-top' ) + .selectOption( 'Edit' ); + await page.locator( '#doaction' ).click(); + + await expect( + await page.locator( '#bulk-titles-list li' ).count() + ).toEqual( products.length ); + } ); + + await test.step( 'update the regular price', async () => { + await page + .locator( 'select[name="change_regular_price"]' ) + .selectOption( 'Increase existing price by (fixed amount or %):' ); + await page + .getByPlaceholder( 'Enter price ($)' ) + .fill( `${ regularPriceIncrease }%` ); + } ); + + await test.step( 'update the sale price', async () => { + await page + .locator( 'select[name="change_sale_price"]' ) + .selectOption( + 'Set to regular price decreased by (fixed amount or %):' + ); + await page + .getByPlaceholder( 'Enter sale price ($)' ) + .fill( `${ salePriceDecrease }%` ); + } ); + + await test.step( 'update the stock quantity', async () => { + await page + .locator( 'select[name="change_stock"]' ) + .selectOption( 'Increase existing stock by:' ); + await page + .getByPlaceholder( 'Stock qty' ) + .fill( `${ stockQtyIncrease }` ); + } ); + + await test.step( 'save the updates', async () => { + await page.getByRole( 'button', { name: 'Update' } ).click(); + } ); + + await test.step( 'verify the changes', async () => { + for ( const product of products ) { + await page.goto( `product/${ product.slug }` ); + + const expectedRegularPrice = ( + product.regular_price * + ( 1 + regularPriceIncrease / 100 ) + ).toFixed( 2 ); + const expectedSalePrice = ( + expectedRegularPrice * + ( 1 - salePriceDecrease / 100 ) + ).toFixed( 2 ); + const expectedStockQty = product.stock_quantity + stockQtyIncrease; + + await expect + .soft( + await page + .locator( 'del' ) + .getByText( `$${ expectedRegularPrice }` ) + .count() + ) + .toBeGreaterThan( 0 ); + await expect + .soft( + await page + .locator( 'ins' ) + .getByText( `$${ expectedSalePrice }` ) + .count() + ) + .toBeGreaterThan( 0 ); + await expect + .soft( page.getByText( `${ expectedStockQty } in stock` ) ) + .toBeVisible(); + } } ); } );