Fix php notice when selecting paid theme (https://github.com/woocommerce/woocommerce-admin/pull/8493)
* Add initial E2E tests for purchase task * Update paid theme logic to remove PHP warning and keep the correct price * Fix php unit tests * Address some PR feedback * Add changelog * Include the purchase task e2e test * Disable test * Delete purchase E2E test file
This commit is contained in:
parent
c05605fddf
commit
4bff4d1302
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: Fix
|
||||
|
||||
Fix handling of paid themes in purchase task. #8493
|
|
@ -92,12 +92,10 @@ class Theme extends Component {
|
|||
location,
|
||||
} );
|
||||
|
||||
if ( slug !== activeTheme && getPriceValue( price ) <= 0 ) {
|
||||
if ( isInstalled ) {
|
||||
this.activateTheme( slug );
|
||||
} else {
|
||||
this.installTheme( slug );
|
||||
}
|
||||
if ( slug !== activeTheme && isInstalled ) {
|
||||
this.activateTheme( slug );
|
||||
} else if ( slug !== activeTheme && getPriceValue( price ) <= 0 ) {
|
||||
this.installTheme( slug );
|
||||
} else {
|
||||
updateProfileItems( { theme: slug } );
|
||||
}
|
||||
|
|
|
@ -9,12 +9,16 @@ import { Page } from 'puppeteer';
|
|||
import { BusinessSection } from '../sections/onboarding/BusinessSection';
|
||||
import { IndustrySection } from '../sections/onboarding/IndustrySection';
|
||||
import { ProductTypeSection } from '../sections/onboarding/ProductTypesSection';
|
||||
import { StoreDetailsSection } from '../sections/onboarding/StoreDetailsSection';
|
||||
import {
|
||||
StoreDetails,
|
||||
StoreDetailsSection,
|
||||
} from '../sections/onboarding/StoreDetailsSection';
|
||||
import { ThemeSection } from '../sections/onboarding/ThemeSection';
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { expect } = require( '@jest/globals' );
|
||||
const config = require( 'config' );
|
||||
|
||||
export class OnboardingWizard extends BasePage {
|
||||
url = 'wp-admin/admin.php?page=wc-admin&path=/setup-wizard';
|
||||
|
@ -79,4 +83,75 @@ export class OnboardingWizard extends BasePage {
|
|||
async goToOBWStep( step: string ): Promise< void > {
|
||||
await this.clickElementWithText( 'span', step );
|
||||
}
|
||||
|
||||
async walkThroughAndCompleteOnboardingWizard(
|
||||
options: {
|
||||
storeDetails?: StoreDetails;
|
||||
industries?: string[];
|
||||
products?: string[];
|
||||
businessDetails?: {
|
||||
productNumber: string;
|
||||
currentlySelling: string;
|
||||
};
|
||||
themeTitle?: string;
|
||||
} = {}
|
||||
): Promise< void > {
|
||||
await this.navigate();
|
||||
await this.storeDetails.completeStoreDetailsSection(
|
||||
options.storeDetails
|
||||
);
|
||||
|
||||
// Wait for "Continue" button to become active
|
||||
await this.continue();
|
||||
|
||||
// Wait for usage tracking pop-up window to appear
|
||||
await this.optionallySelectUsageTracking();
|
||||
// Query for the industries checkboxes
|
||||
await this.industry.isDisplayed();
|
||||
const industries = options.industries || [ 'Other' ];
|
||||
for ( const industry of industries ) {
|
||||
await this.industry.selectIndustry( industry );
|
||||
}
|
||||
await this.continue();
|
||||
await this.productTypes.isDisplayed( 7 );
|
||||
const products = options.products || [
|
||||
'Physical products',
|
||||
'Downloads',
|
||||
];
|
||||
for ( const product of products ) {
|
||||
await this.productTypes.selectProduct( product );
|
||||
}
|
||||
|
||||
await this.continue();
|
||||
await page.waitForNavigation( {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
await this.business.isDisplayed();
|
||||
|
||||
const businessDetails = options.businessDetails || {
|
||||
productNumber: config.get( 'onboardingwizard.numberofproducts' ),
|
||||
currentlySelling: config.get( 'onboardingwizard.sellingelsewhere' ),
|
||||
};
|
||||
await this.business.selectProductNumber(
|
||||
businessDetails.productNumber
|
||||
);
|
||||
await this.business.selectCurrentlySelling(
|
||||
businessDetails.currentlySelling
|
||||
);
|
||||
|
||||
await this.continue();
|
||||
await this.business.freeFeaturesIsDisplayed();
|
||||
await this.business.expandRecommendedBusinessFeatures();
|
||||
await this.business.uncheckAllRecommendedBusinessFeatures();
|
||||
|
||||
await this.continue();
|
||||
await this.themes.isDisplayed();
|
||||
|
||||
// This navigates to the home screen
|
||||
if ( options.themeTitle ) {
|
||||
await this.themes.continueWithTheme( options.themeTitle );
|
||||
} else {
|
||||
await this.themes.continueWithActiveTheme();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ const {
|
|||
const config = require( 'config' );
|
||||
/* eslint-enable @typescript-eslint/no-var-requires */
|
||||
|
||||
interface StoreDetails {
|
||||
export interface StoreDetails {
|
||||
addressLine1?: string;
|
||||
addressLine2?: string;
|
||||
countryRegionSubstring?: string;
|
||||
|
|
|
@ -13,4 +13,17 @@ export class ThemeSection extends BasePage {
|
|||
async continueWithActiveTheme(): Promise< void > {
|
||||
await this.clickButtonWithText( 'Continue with my active theme' );
|
||||
}
|
||||
|
||||
async continueWithTheme( themeTitle: string ): Promise< void > {
|
||||
const title = await waitForElementByText( 'h2', themeTitle );
|
||||
const card = await title?.evaluateHandle( ( element ) => {
|
||||
return element.closest( '.components-card' );
|
||||
} );
|
||||
const chooseButton = await card
|
||||
?.asElement()
|
||||
?.$x( `//button[contains(text(), "Choose")]` );
|
||||
if ( chooseButton && chooseButton.length > 0 ) {
|
||||
await chooseButton[ 0 ].click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,5 +4,6 @@ export * from './analytics/analytics';
|
|||
export * from './analytics/analytics-overview';
|
||||
export * from './marketing/coupons';
|
||||
export * from './tasks/payment';
|
||||
export * from './tasks/purchase';
|
||||
export * from './homescreen/task-list';
|
||||
export * from './homescreen/activity-panel';
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { resetWooCommerceState } from '../../fixtures';
|
||||
import { Login } from '../../pages/Login';
|
||||
import { OnboardingWizard } from '../../pages/OnboardingWizard';
|
||||
import { WcHomescreen } from '../../pages/WcHomescreen';
|
||||
import { getElementByText, waitForElementByText } from '../../utils/actions';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { afterAll, beforeAll, describe, it } = require( '@jest/globals' );
|
||||
/* eslint-enable @typescript-eslint/no-var-requires */
|
||||
|
||||
const testAdminPurchaseSetupTask = () => {
|
||||
describe( 'Purchase setup task', () => {
|
||||
const profileWizard = new OnboardingWizard( page );
|
||||
const homeScreen = new WcHomescreen( page );
|
||||
const login = new Login( page );
|
||||
|
||||
beforeAll( async () => {
|
||||
await login.login();
|
||||
} );
|
||||
|
||||
afterAll( async () => {
|
||||
await login.logout();
|
||||
} );
|
||||
|
||||
describe( 'selecting paid product', () => {
|
||||
beforeAll( async () => {
|
||||
await resetWooCommerceState();
|
||||
|
||||
await profileWizard.navigate();
|
||||
await profileWizard.walkThroughAndCompleteOnboardingWizard( {
|
||||
products: [ 'Memberships' ],
|
||||
} );
|
||||
|
||||
await homeScreen.isDisplayed();
|
||||
await homeScreen.possiblyDismissWelcomeModal();
|
||||
} );
|
||||
|
||||
it( 'should display add <product name> to my store task', async () => {
|
||||
expect(
|
||||
await getElementByText( '*', 'Add Memberships to my store' )
|
||||
).toBeDefined();
|
||||
} );
|
||||
|
||||
it( 'should show paid features modal with option to buy now', async () => {
|
||||
const task = await getElementByText(
|
||||
'*',
|
||||
'Add Memberships to my store'
|
||||
);
|
||||
await task?.click();
|
||||
await waitForElementByText(
|
||||
'h1',
|
||||
'Would you like to add the following paid features to your store now?'
|
||||
);
|
||||
expect(
|
||||
await getElementByText( 'button', 'Buy now' )
|
||||
).toBeDefined();
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'selecting paid theme', () => {
|
||||
beforeAll( async () => {
|
||||
await resetWooCommerceState();
|
||||
|
||||
await profileWizard.navigate();
|
||||
await profileWizard.walkThroughAndCompleteOnboardingWizard( {
|
||||
themeTitle: 'Blooms',
|
||||
} );
|
||||
|
||||
await homeScreen.isDisplayed();
|
||||
await homeScreen.possiblyDismissWelcomeModal();
|
||||
} );
|
||||
|
||||
it( 'should display add <theme name> to my store task', async () => {
|
||||
expect(
|
||||
await getElementByText( '*', 'Add Blooms to my store' )
|
||||
).toBeDefined();
|
||||
} );
|
||||
|
||||
it( 'should show paid features modal with option to buy now', async () => {
|
||||
const task = await getElementByText(
|
||||
'*',
|
||||
'Add Blooms to my store'
|
||||
);
|
||||
await task?.click();
|
||||
await waitForElementByText(
|
||||
'h1',
|
||||
'Would you like to add the following paid features to your store now?'
|
||||
);
|
||||
expect(
|
||||
await getElementByText( 'button', 'Buy now' )
|
||||
).toBeDefined();
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
module.exports = { testAdminPurchaseSetupTask };
|
|
@ -60,7 +60,7 @@ class OnboardingThemes {
|
|||
$themes = self::get_themes();
|
||||
$theme_key = array_search( $slug, array_column( $themes, 'slug' ), true );
|
||||
$theme = false !== $theme_key ? $themes[ $theme_key ] : null;
|
||||
if ( $theme && isset( $theme['id'] ) && isset( $theme['price'] ) && ( ! isset( $theme['is_installed'] ) || ! $theme['is_installed'] ) ) {
|
||||
if ( $theme && isset( $theme['id'] ) && isset( $theme['price'] ) ) {
|
||||
$price = self::get_price_from_string( $theme['price'] );
|
||||
if ( $price && $price > 0 ) {
|
||||
return $themes[ $theme_key ];
|
||||
|
@ -123,8 +123,13 @@ class OnboardingThemes {
|
|||
$active_theme = get_option( 'stylesheet' );
|
||||
|
||||
foreach ( $installed_themes as $slug => $theme ) {
|
||||
$theme_data = self::get_theme_data( $theme );
|
||||
$themes[ $slug ] = $theme_data;
|
||||
$theme_data = self::get_theme_data( $theme );
|
||||
if ( isset( $themes[ $slug ] ) ) {
|
||||
$themes[ $slug ]['is_installed'] = true;
|
||||
$themes[ $slug ]['image'] = $theme_data['image'];
|
||||
} else {
|
||||
$themes[ $slug ] = $theme_data;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the WooCommerce support tag for default themes that don't explicitly declare support.
|
||||
|
|
|
@ -6,7 +6,6 @@ use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProducts;
|
|||
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingThemes;
|
||||
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
|
||||
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
|
||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||
|
||||
/**
|
||||
* Purchase Task
|
||||
|
@ -55,7 +54,7 @@ class Purchase extends Task {
|
|||
* @return string
|
||||
*/
|
||||
public function get_title() {
|
||||
$products = $this->get_products();
|
||||
$products = $this->get_paid_products_and_themes();
|
||||
|
||||
return count( $products['remaining'] ) === 1
|
||||
? sprintf(
|
||||
|
@ -78,19 +77,20 @@ class Purchase extends Task {
|
|||
* @return string
|
||||
*/
|
||||
public function get_content() {
|
||||
$products = $this->get_products();
|
||||
$products = $this->get_paid_products_and_themes();
|
||||
|
||||
return count( $products['remaining'] ) === 1
|
||||
? $products['purchaseable'][0]['description']
|
||||
: sprintf(
|
||||
/* translators: %1$s: list of product names comma separated, %2%s the last product name */
|
||||
__(
|
||||
'Good choice! You chose to add %1$s and %2$s to your store.',
|
||||
'woocommerce-admin'
|
||||
),
|
||||
implode( ', ', array_slice( $products['remaining'], 0, -1 ) ) . ( count( $products['remaining'] ) > 2 ? ',' : '' ),
|
||||
end( $products['remaining'] )
|
||||
);
|
||||
if ( count( $products['remaining'] ) === 1 ) {
|
||||
return isset( $products['purchaseable'][0]['description'] ) ? $products['purchaseable'][0]['description'] : $products['purchaseable'][0]['excerpt'];
|
||||
}
|
||||
return sprintf(
|
||||
/* translators: %1$s: list of product names comma separated, %2%s the last product name */
|
||||
__(
|
||||
'Good choice! You chose to add %1$s and %2$s to your store.',
|
||||
'woocommerce-admin'
|
||||
),
|
||||
implode( ', ', array_slice( $products['remaining'], 0, -1 ) ) . ( count( $products['remaining'] ) > 2 ? ',' : '' ),
|
||||
end( $products['remaining'] )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,7 @@ class Purchase extends Task {
|
|||
* @return bool
|
||||
*/
|
||||
public function is_complete() {
|
||||
$products = $this->get_products();
|
||||
$products = $this->get_paid_products_and_themes();
|
||||
return count( $products['remaining'] ) === 0;
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ class Purchase extends Task {
|
|||
* @return bool
|
||||
*/
|
||||
public function can_view() {
|
||||
$products = $this->get_products();
|
||||
$products = $this->get_paid_products_and_themes();
|
||||
return count( $products['purchaseable'] ) > 0;
|
||||
}
|
||||
|
||||
|
@ -146,18 +146,17 @@ class Purchase extends Task {
|
|||
*
|
||||
* @return array purchaseable and remaining products and themes.
|
||||
*/
|
||||
public static function get_products() {
|
||||
public static function get_paid_products_and_themes() {
|
||||
$relevant_products = OnboardingProducts::get_relevant_products();
|
||||
|
||||
$profiler_data = get_option( OnboardingProfile::DATA_OPTION, array() );
|
||||
$theme = isset( $profiler_data['theme'] ) ? $profiler_data['theme'] : null;
|
||||
$paid_theme = $theme ? OnboardingThemes::get_paid_theme_by_slug( $theme ) : null;
|
||||
$installed = PluginsHelper::get_installed_plugin_slugs();
|
||||
if ( $paid_theme ) {
|
||||
|
||||
$relevant_products['purchaseable'][] = $paid_theme;
|
||||
|
||||
if ( ! in_array( $paid_theme['slug'], $installed, true ) ) {
|
||||
if ( isset( $paid_theme['is_installed'] ) && false === $paid_theme['is_installed'] ) {
|
||||
$relevant_products['remaining'][] = $paid_theme['title'];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,12 +32,16 @@ class WC_Tests_OnboardingTasks_Task_Purchase extends WC_Unit_Test_Case {
|
|||
set_transient(
|
||||
OnboardingThemes::THEMES_TRANSIENT,
|
||||
array(
|
||||
'free' => array( 'slug' => 'free' ),
|
||||
'free' => array(
|
||||
'slug' => 'free',
|
||||
'is_installed' => false,
|
||||
),
|
||||
'paid' => array(
|
||||
'slug' => 'paid',
|
||||
'id' => 12312,
|
||||
'price' => '$79.00',
|
||||
'title' => 'theme title',
|
||||
'slug' => 'paid',
|
||||
'id' => 12312,
|
||||
'price' => '$79.00',
|
||||
'title' => 'theme title',
|
||||
'is_installed' => false,
|
||||
),
|
||||
'paid_installed' => array(
|
||||
'slug' => 'paid_installed',
|
||||
|
@ -47,10 +51,11 @@ class WC_Tests_OnboardingTasks_Task_Purchase extends WC_Unit_Test_Case {
|
|||
'is_installed' => true,
|
||||
),
|
||||
'free_with_price' => array(
|
||||
'slug' => 'free_with_price',
|
||||
'id' => 12312,
|
||||
'price' => '$0.00',
|
||||
'title' => 'theme title',
|
||||
'slug' => 'free_with_price',
|
||||
'id' => 12312,
|
||||
'price' => '$0.00',
|
||||
'title' => 'theme title',
|
||||
'is_installed' => false,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue