Skip to content

Commit b810a35

Browse files
author
Soare Robert-Daniel
committed
dev: add E2E tests
1 parent 731a2ca commit b810a35

5 files changed

Lines changed: 396 additions & 49 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
/**
3+
* Seeds a PPOM field group containing pro-gated quantity and price-matrix fields.
4+
*
5+
* This runs through WP-CLI inside wp-env so the storefront E2E can cover the
6+
* runtime behavior even when the free admin builder hides these field types.
7+
*/
8+
9+
if ( ! defined( 'ABSPATH' ) ) {
10+
exit( 1 );
11+
}
12+
13+
global $args, $wpdb;
14+
15+
$suffix = isset( $args[0] ) ? sanitize_key( $args[0] ) : (string) time();
16+
17+
$product_id = (int) $wpdb->get_var(
18+
$wpdb->prepare(
19+
"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s AND post_title = %s ORDER BY ID DESC LIMIT 1",
20+
'product',
21+
'publish',
22+
'Product 1'
23+
)
24+
);
25+
26+
if ( ! $product_id ) {
27+
echo wp_json_encode(
28+
array(
29+
'status' => 'error',
30+
'message' => 'Product 1 not found',
31+
)
32+
);
33+
exit( 1 );
34+
}
35+
36+
$fields = array(
37+
array(
38+
'type' => 'pricematrix',
39+
'title' => 'Matrix Pricing',
40+
'data_name'=> 'price_matrix_' . $suffix,
41+
'qty_step' => '2',
42+
'options' => array(
43+
array(
44+
'option' => '2-2',
45+
'price' => '8',
46+
'label' => 'Qty 2',
47+
'id' => 'qty_2',
48+
),
49+
array(
50+
'option' => '4-4',
51+
'price' => '7',
52+
'label' => 'Qty 4',
53+
'id' => 'qty_4',
54+
),
55+
),
56+
),
57+
array(
58+
'type' => 'quantities',
59+
'title' => 'Seats',
60+
'data_name' => 'seat_quantity_' . $suffix,
61+
'view_control' => 'simple_view',
62+
'min_qty' => '2',
63+
'max_qty' => '4',
64+
'options' => array(
65+
array(
66+
'option' => 'seat',
67+
'price' => '',
68+
'weight' => '',
69+
'default' => '0',
70+
'min' => '0',
71+
'max' => '4',
72+
'stock' => '',
73+
),
74+
),
75+
),
76+
);
77+
78+
$meta_name = 'Quantity Matrix ' . $suffix;
79+
$ppom_table = $wpdb->prefix . PPOM_TABLE_META;
80+
81+
$wpdb->insert(
82+
$ppom_table,
83+
array(
84+
'productmeta_name' => $meta_name,
85+
'productmeta_validation' => 'no',
86+
'dynamic_price_display' => 'no',
87+
'send_file_attachment' => '',
88+
'show_cart_thumb' => 'no',
89+
'aviary_api_key' => '',
90+
'productmeta_style' => '',
91+
'productmeta_categories' => '',
92+
'the_meta' => wp_json_encode( $fields ),
93+
'productmeta_created' => current_time( 'mysql' ),
94+
)
95+
);
96+
97+
$meta_id = (int) $wpdb->insert_id;
98+
99+
if ( ! $meta_id ) {
100+
echo wp_json_encode(
101+
array(
102+
'status' => 'error',
103+
'message' => 'Unable to create PPOM meta row',
104+
)
105+
);
106+
exit( 1 );
107+
}
108+
109+
$fields = apply_filters( 'ppom_meta_data_saving', $fields, $meta_id );
110+
ppom_admin_update_ppom_meta_only( $meta_id, $fields );
111+
update_post_meta( $product_id, PPOM_PRODUCT_META_KEY, $meta_id );
112+
113+
echo wp_json_encode(
114+
array(
115+
'status' => 'success',
116+
'meta_id' => $meta_id,
117+
'product_id' => $product_id,
118+
'product_permalink' => get_permalink( $product_id ),
119+
'quantity_field_id' => 'seat_quantity_' . $suffix,
120+
)
121+
);

tests/e2e/specs/checkout-critical.spec.js

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { test, expect } from '@wordpress/e2e-test-utils-playwright';
55

66
import {
77
addNewField,
8+
attachGroupToProduct,
9+
clearCart,
810
fillFieldNameAndId,
911
pickFieldTypeInModal,
1012
saveFieldInModal,
@@ -50,39 +52,6 @@ function formatPrice( priceText, amount ) {
5052
);
5153
}
5254

53-
async function clearCart( page ) {
54-
await page.goto( '/cart/' );
55-
await page.waitForLoadState( 'networkidle' );
56-
57-
const removeButtons = page.getByRole( 'button', {
58-
name: /Remove .* from cart/,
59-
} );
60-
61-
while ( await removeButtons.count() ) {
62-
const buttonCount = await removeButtons.count();
63-
await removeButtons.first().click();
64-
await expect( removeButtons ).toHaveCount( buttonCount - 1 );
65-
}
66-
}
67-
68-
async function attachGroupToProduct( page, productName ) {
69-
await page.getByText( 'Attach to Products' ).click( { force: true } );
70-
await page.waitForLoadState( 'networkidle' );
71-
72-
const productSelector = page.locator(
73-
'select[name="ppom-attach-to-products\\[\\]"]'
74-
);
75-
76-
await productSelector.selectOption( { label: productName } );
77-
78-
const productId = await productSelector.inputValue();
79-
80-
await page.getByRole( 'button', { name: 'Save', exact: true } ).click();
81-
await page.waitForLoadState( 'networkidle' );
82-
83-
return productId;
84-
}
85-
8655
async function fillCheckoutAddress( page ) {
8756
const emailField = page.getByRole( 'textbox', {
8857
name: 'Email address',
@@ -157,9 +126,13 @@ test.describe( 'Critical Checkout Flow', () => {
157126
parsePrice( priceText ) + Number( FIELD_PRICE )
158127
);
159128

160-
const addToCartButton = page.getByRole( 'button', {
161-
name: 'Add to cart',
162-
} );
129+
const addToCartButton = page.locator( 'form.cart' ).getByRole(
130+
'button',
131+
{
132+
name: 'Add to cart',
133+
exact: true,
134+
}
135+
);
163136

164137
await addToCartButton.click();
165138
await expect( page.locator( 'body' ) ).toContainText(

tests/e2e/specs/conditions.spec.js

Lines changed: 121 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { test, expect } from '@wordpress/e2e-test-utils-playwright';
66
import {
77
addNewField,
88
addNewOptionInModal,
9+
attachGroupToProduct,
10+
clearCart,
911
enableConditionsInModal,
1012
fillFieldNameAndId,
1113
fillOptionNameAndValue,
@@ -15,6 +17,8 @@ import {
1517
switchToConditionsModalTab,
1618
} from '../utils';
1719

20+
const RUN_SUFFIX = Date.now();
21+
1822
test.describe( 'Conditions', () => {
1923
/***
2024
* Create two select fields (with two options each) and one text field. Display the text field if the second option of the second select is selected.
@@ -105,21 +109,10 @@ test.describe( 'Conditions', () => {
105109
await page.waitForLoadState( 'networkidle' );
106110

107111
await page.reload();
108-
await page.getByText( 'Attach to Products' ).click( { force: true } );
109-
await page.waitForLoadState( 'networkidle' );
110-
111-
const productSelector = page.locator(
112-
'select[name="ppom-attach-to-products\\[\\]"]'
113-
);
114-
await page.waitForLoadState( 'networkidle' );
115112

116-
await productSelector.selectOption( { index: 0 } );
117-
const selectedOption = await productSelector.inputValue();
118-
console.log( 'Selected option value:', selectedOption );
119-
await page.getByRole( 'button', { name: 'Save', exact: true } ).click();
113+
const productId = await attachGroupToProduct( page, 'Product 1' );
120114

121-
await page.waitForLoadState( 'networkidle' );
122-
await page.goto( `/?p=${ selectedOption }` );
115+
await page.goto( `/?p=${ productId }` );
123116

124117
await expect( page.getByLabel( 'Output' ) ).toBeHidden();
125118

@@ -131,4 +124,119 @@ test.describe( 'Conditions', () => {
131124

132125
await expect( page.getByLabel( 'Output' ) ).toBeVisible();
133126
} );
127+
128+
test( '@critical hidden required fields stop blocking only after the condition hides them', async ( {
129+
page,
130+
admin,
131+
} ) => {
132+
const selectFieldId = `condition_gate_${ RUN_SUFFIX }`;
133+
const outputFieldId = `conditional_output_${ RUN_SUFFIX }`;
134+
const outputError = 'Please enter the revealed value';
135+
136+
await clearCart( page );
137+
await admin.visitAdminPage( 'admin.php?page=ppom' );
138+
139+
await page.getByRole( 'link', { name: 'Add New Group' } ).click();
140+
await page
141+
.getByRole( 'textbox' )
142+
.fill( `Required Conditions ${ RUN_SUFFIX }` );
143+
144+
await addNewField( page );
145+
await pickFieldTypeInModal( page, 'select' );
146+
await fillFieldNameAndId( page, 1, 'Visibility Gate', selectFieldId );
147+
148+
await page
149+
.locator( '#ppom_field_model_1' )
150+
.getByText( 'Add Options', { exact: true } )
151+
.click();
152+
await fillOptionNameAndValue( page, 1, 0, 'Hide output', 'hide_output' );
153+
await addNewOptionInModal( page, 1 );
154+
await fillOptionNameAndValue( page, 1, 1, 'Show output', 'show_output' );
155+
await saveFieldInModal( page, 1 );
156+
157+
await addNewField( page );
158+
await pickFieldTypeInModal( page, 'text' );
159+
await fillFieldNameAndId( page, 2, 'Conditional Output', outputFieldId );
160+
await page
161+
.locator( 'input[name="ppom\\[2\\]\\[error_message\\]"]' )
162+
.fill( outputError );
163+
await page
164+
.locator( 'input[name="ppom\\[2\\]\\[required\\]"]' )
165+
.check( { force: true } );
166+
await saveFieldInModal( page, 2 );
167+
168+
await saveFields( page );
169+
await page.waitForLoadState( 'networkidle' );
170+
await page.reload();
171+
172+
await page.locator( '#ppom_sort_id_2 .ppom-edit-field' ).click();
173+
await switchToConditionsModalTab( page, 2 );
174+
await enableConditionsInModal( page, 2 );
175+
176+
await page
177+
.locator(
178+
'select[name="ppom\\[2\\]\\[conditions\\]\\[rules\\]\\[0\\]\\[elements\\]"]'
179+
)
180+
.selectOption( selectFieldId );
181+
await page
182+
.locator(
183+
'select[name="ppom\\[2\\]\\[conditions\\]\\[rules\\]\\[0\\]\\[operators\\]"]'
184+
)
185+
.selectOption( { index: 0 } );
186+
await page
187+
.locator(
188+
'select[name="ppom\\[2\\]\\[conditions\\]\\[rules\\]\\[0\\]\\[element_values\\]"]'
189+
)
190+
.selectOption( { index: 1 } );
191+
192+
await saveFieldInModal( page, 2 );
193+
await saveFields( page );
194+
await page.waitForLoadState( 'networkidle' );
195+
await page.reload();
196+
197+
const productId = await attachGroupToProduct( page, 'Product 1' );
198+
199+
await page.goto( `/?p=${ productId }` );
200+
await expect( page.getByLabel( 'Conditional Output' ) ).toBeHidden();
201+
202+
const addToCartButton = page.locator( 'form.cart' ).getByRole(
203+
'button',
204+
{
205+
name: 'Add to cart',
206+
exact: true,
207+
}
208+
);
209+
210+
await addToCartButton.click();
211+
await page.waitForLoadState( 'networkidle' );
212+
await page.goto( '/cart/' );
213+
await expect( page.getByText( 'Product 1' ) ).toBeVisible();
214+
await expect( page.locator( 'body' ) ).not.toContainText( outputError );
215+
216+
await clearCart( page );
217+
await page.goto( `/?p=${ productId }` );
218+
await page
219+
.locator( `select[name="ppom[fields][${ selectFieldId }]"]` )
220+
.selectOption( { index: 1 } );
221+
222+
const outputInput = page.locator(
223+
`input[name="ppom[fields][${ outputFieldId }]"]`
224+
);
225+
226+
await expect( outputInput ).toBeVisible();
227+
await addToCartButton.click();
228+
await expect( page.locator( 'body' ) ).toContainText(
229+
`Conditional Output: ${ outputError }`
230+
);
231+
232+
await outputInput.fill( 'Condition satisfied' );
233+
await addToCartButton.click();
234+
await page.waitForLoadState( 'networkidle' );
235+
await page.goto( '/cart/' );
236+
237+
await expect( page.getByText( 'Product 1' ) ).toBeVisible();
238+
await expect( page.locator( 'body' ) ).toContainText(
239+
'Condition satisfied'
240+
);
241+
} );
134242
} );

0 commit comments

Comments
 (0)