Add Behat tests for sorting zones by priority

This commit is contained in:
Tomasz Kaliński 2025-09-16 13:55:20 +02:00
parent 03c714d462
commit fa683584db
15 changed files with 213 additions and 4 deletions

View file

@ -67,3 +67,13 @@ Feature: Editing a zone
And I save my changes
Then I should be notified that it has been successfully edited
And this zone name should be "EU"
@api @ui
Scenario: Setting zone to the lowest priority
Given the store has a zone "European Union" with code "EU" and priority 0
And it has the "France" country member
When I want to modify the zone named "European Union"
And I set its priority to "-1"
And I save my changes
Then I should be notified that it has been successfully edited
And the "European Union" zone should have priority 3

View file

@ -0,0 +1,26 @@
@managing_zones
Feature: Editing a zone
In order to change my my tax and shipping configuration
As an Administrator
I want to be able to edit a zone
Background:
Given the store also has country "France"
And the store has a zone "North America" with code "NA" and priority 2
And the store has a zone "South America" with code "SA" and priority 1
And the store has a zone "Australia" with code "AU" and priority 0
And I am logged in as an administrator
@api @ui
Scenario: Zones are sorted by priority in descending order by default
When I want to see all zones in store
Then I should see 3 zones in the list
Then the first zone on the list should have name "North America"
Then the last zone on the list should have name "Australia"
@api @ui
Scenario: Zone's default priority is 0 which puts it at the bottom of the list
Given the store has a zone "European Union" with code "EU"
When I want to see all zones in store
Then I should see 4 zones in the list
And the last zone on the list should have name "European Union"

View file

@ -0,0 +1,49 @@
@applying_taxes
Feature: Apply taxes based on zone priority
In order to pay correct taxes when a country belongs to multiple zones
As a Customer
I want the zone with higher priority to be used for tax calculation
Background:
Given the store operates on a single channel
Given the store operates in "France" and "Belgium"
And there is a zone "The Rest of the World" containing all other countries
And the store has a zone "European Union" with code "EU" and priority 2
And it has the "France" country member
And it also has the "Belgium" country member
And default tax zone is "RoW"
And the store has "No tax" tax rate of 0% for "Clothes" for the rest of the world
And the store has "VAT" tax rate of 23% for "Clothes" within the "European Union" zone
And the store has a product "T-Shirt" priced at "$100.00"
And it belongs to "Clothes" tax category
And I am a logged in customer
@api @ui
Scenario: Applying tax from the higher priority zone
Given I added product "T-Shirt" to the cart
And I addressed the cart to "Belgium"
When I check the details of my cart
Then my cart total should be "$123.00"
And my cart taxes should be "$23.00"
@api @ui
Scenario: Applying tax from new zone zone when it has higher priority
Given the store has a zone "Benelux countries" with code "BC" and priority 3
And it also has the "Belgium" country member
And the store has "VAT" tax rate of 0% for "Clothes" within the "Benelux countries" zone
And I added product "T-Shirt" to the cart
And I addressed the cart to "Belgium"
When I check the details of my cart
Then my cart total should be "$100.00"
And there should be no taxes charged
@api @ui
Scenario: Applying tax from current zone when the new one has lower priority
Given the store has a zone "Benelux countries" with code "GU" and priority 1
And it also has the "Belgium" country member
And the store has "VAT" tax rate of 0% for "Clothes" within the "Benelux countries" zone
And I added product "T-Shirt" to the cart
And I addressed the cart to "Belgium"
When I check the details of my cart
Then my cart total should be "$123.00"
And my cart taxes should be "$23.00"

View file

@ -129,6 +129,14 @@ final readonly class ManagingZonesContext implements Context
$this->client->addRequestData('scope', $scope);
}
/**
* @When I set its priority to :priority
*/
public function iSetsItsPriorityTo(int $priority): void
{
$this->client->addRequestData('priority', $priority);
}
/**
* @When I (try to) add it
*/
@ -496,6 +504,37 @@ final readonly class ManagingZonesContext implements Context
);
}
/**
* @Then /^the (first|last) zone on the list should have ([^"]+) "([^"]+)"$/
*/
public function theFirstZoneOnTheListShouldHave(string $togglePosition, string $field, string $value): void
{
$items = $this->responseChecker->getValue($this->client->getLastResponse(), 'hydra:member');
if ('first' === $togglePosition) {
$item = reset($items);
} else {
$item = end($items);
}
Assert::same($item[$field], $value);
}
/**
* @Then the :zone zone should have priority :priority
*/
public function theZoneShouldHavePriority(ZoneInterface $zone, int $priority): void
{
Assert::true(
$this->responseChecker->hasItemWithValues(
$this->client->index(Resources::ZONES),
[
'name' => $zone->getName(),
'priority' => $priority,
],
),
);
}
private function removeZoneMember(CountryInterface|ProvinceInterface|ZoneInterface $objectToRemove): void
{
$members = $this->client->getContent()['members'];

View file

@ -84,12 +84,17 @@ final readonly class ZoneContext implements Context
* @Given the store has (also) a zone :zoneName
* @Given the store has a zone :zoneName with code :code
* @Given the store also has a zone :zoneName with code :code
* @Given the store has a zone :zoneName with code :code and priority :priority
*/
public function theStoreHasAZoneWithCode(string $zoneName, ?string $code = null): void
public function theStoreHasAZoneWithCode(string $zoneName, ?string $code = null, ?int $priority = 0): void
{
$this->saveZone($this->createZone($zoneName, $code, Scope::ALL), 'zone');
$zone = $this->createZone($zoneName, $code, Scope::ALL);
$zone->setPriority($priority);
$this->saveZone($zone, 'zone');
}
/**
* @Given the store has zones :firstName, :secondName and :thirdName
*/

View file

@ -132,6 +132,14 @@ final class ManagingZonesContext implements Context
$this->formElement->selectScope($scope);
}
/**
* @When I set its priority to :priority
*/
public function iSetItsPriorityTo(int $priority): void
{
$this->formElement->prioritizeIt($priority);
}
/**
* @When I add it
* @When I try to add it
@ -338,4 +346,45 @@ final class ManagingZonesContext implements Context
throw new \InvalidArgumentException(sprintf('Member "%s" should not be selectable.', $name));
}
/**
* @Then the first zone on the list should have :field :value
*/
public function theFirstZoneOnTheListShouldHave(string $field, string $value): void
{
$fields = $this->indexPage->getColumnFields($field);
$actualValue = reset($fields);
Assert::same(
$actualValue,
$value,
sprintf('Expected first zone\'s %s to be "%s", but it is "%s".', $field, $value, $actualValue),
);
}
/**
* @Then the last zone on the list should have :field :value
*/
public function theLastZoneOnTheListShouldHave(string $field, string $value): void
{
$fields = $this->indexPage->getColumnFields($field);
$actualValue = end($fields);
Assert::same(
$actualValue,
$value,
sprintf('Expected last zone\'s %s to be "%s", but it is "%s".', $field, $value, $actualValue),
);
}
/**
* @Given the :zone zone should have priority :priority
*/
public function theZoneShouldHavePriority(ZoneInterface $zone, int $priority)
{
$this->iWantToModifyAZoneNamed($zone);
Assert::same($this->formElement->getPriority(), $priority);
}
}

View file

@ -31,6 +31,11 @@ class FormElement extends BaseFormElement implements FormElementInterface
return $this->getElement('name')->getValue();
}
public function getPriority(): int
{
return (int) $this->getElement('priority')->getValue();
}
public function getType(): string
{
return $this->getElement('type')->getValue();
@ -67,6 +72,12 @@ class FormElement extends BaseFormElement implements FormElementInterface
$this->waitForElement(5, 'zone_member_added');
}
public function prioritizeIt(int $priority): void
{
$this->getElement('priority')->setValue($priority);
}
public function removeMember(string $member): void
{
$this->getElement('zone_member_delete', ['%name%' => $member])->click();
@ -100,6 +111,7 @@ class FormElement extends BaseFormElement implements FormElementInterface
'code' => '[data-test-code]',
'form_validation_message' => 'form > div.alert.alert-danger.d-block',
'name' => '[data-test-name]',
'priority' => '#sylius_admin_zone_priority',
'scope' => '[data-test-scope]',
'type' => '[data-test-type]',
'zone_member' => '[data-test-zone-member]:contains("%name%")',

View file

@ -19,6 +19,8 @@ interface FormElementInterface extends BaseFormElementInterface
{
public function getName(): string;
public function getPriority(): int;
public function nameIt(string $name): void;
public function getType(): string;
@ -31,6 +33,8 @@ interface FormElementInterface extends BaseFormElementInterface
public function addMember(): void;
public function prioritizeIt(int $priority): void;
public function getScope(): string;
public function selectScope(string $scope): void;

View file

@ -5,6 +5,8 @@ sylius_grid:
name: doctrine/orm
options:
class: "%sylius.model.zone.class%"
sorting:
priority: desc
fields:
priority:
type: twig

View file

@ -41,6 +41,12 @@
<group>sylius:admin:zone:index</group>
<group>sylius:admin:zone:show</group>
</attribute>
<attribute name="priority">
<group>sylius:admin:zone:create</group>
<group>sylius:admin:zone:index</group>
<group>sylius:admin:zone:show</group>
<group>sylius:admin:zone:update</group>
</attribute>
<attribute name="createdAt">
<group>sylius:admin:zone:index</group>
<group>sylius:admin:zone:show</group>

View file

@ -96,7 +96,7 @@ class GeographicalFixture extends AbstractFixture
->arrayNode('zones')->scalarPrototype()->end()->end()
->arrayNode('provinces')->scalarPrototype()->end()->end()
->scalarNode('scope')->end()
->integerNode('priority')->defaultValue(0)->end()
->integerNode('priority')->end()
;
$zoneNode
@ -141,6 +141,8 @@ class GeographicalFixture extends AbstractFixture
/** @param array<string, mixed> $zones */
private function loadZones(array $zones, \Closure $zoneValidator): void
{
$priorityCounter = 0;
foreach ($zones as $zoneCode => $zoneOptions) {
$zoneName = $zoneOptions['name'];
@ -154,7 +156,7 @@ class GeographicalFixture extends AbstractFixture
$zone->setCode($zoneCode);
$zone->setName($zoneName);
$zone->setType($zoneType);
$zone->setPriority($zoneOptions['priority']);
$zone->setPriority($zoneOptions['priority'] ?? $priorityCounter++);
if (isset($zoneOptions['scope'])) {
$zone->setScope($zoneOptions['scope']);

View file

@ -7,6 +7,7 @@
"name": "UnitedStates",
"type": "country",
"scope": "all",
"priority": 0,
"members": [
{
"@type": "ZoneMember",

View file

@ -7,6 +7,7 @@
"name": "European Union",
"type": "country",
"scope": "all",
"priority": 0,
"members": [
{
"@type": "ZoneMember",

View file

@ -11,6 +11,7 @@
"name": "Weimar Triangle",
"type": "country",
"scope": "all",
"priority": 0,
"members": [
{
"@type": "ZoneMember",
@ -34,6 +35,7 @@
"name": "European Union",
"type": "country",
"scope": "all",
"priority": 0,
"members": [
{
"@type": "ZoneMember",

View file

@ -7,6 +7,7 @@
"name": "EuropeanUnion",
"type": "country",
"scope": "all",
"priority": 0,
"members": [
{
"@type": "ZoneMember",