Complex classes like AddressPage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AddressPage, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class AddressPage extends SymfonyPage implements AddressPageInterface |
||
28 | { |
||
29 | public const TYPE_BILLING = 'billing'; |
||
30 | |||
31 | public const TYPE_SHIPPING = 'shipping'; |
||
32 | |||
33 | /** @var AddressFactoryInterface */ |
||
34 | private $addressFactory; |
||
35 | |||
36 | public function __construct( |
||
46 | |||
47 | public function getRouteName(): string |
||
51 | |||
52 | public function chooseDifferentShippingAddress(): void |
||
53 | { |
||
54 | $driver = $this->getDriver(); |
||
55 | if ($driver instanceof Selenium2Driver) { |
||
56 | $this->getElement('different_shipping_address_label')->click(); |
||
57 | |||
58 | return; |
||
59 | } |
||
60 | |||
61 | $billingAddressSwitch = $this->getElement('different_shipping_address'); |
||
62 | Assert::false( |
||
63 | $billingAddressSwitch->isChecked(), |
||
64 | 'Previous state of different billing address switch was true expected to be false' |
||
65 | ); |
||
66 | |||
67 | $billingAddressSwitch->check(); |
||
68 | } |
||
69 | |||
70 | public function checkInvalidCredentialsValidation(): bool |
||
83 | |||
84 | public function checkValidationMessageFor(string $element, string $message): bool |
||
98 | |||
99 | public function specifyShippingAddress(AddressInterface $shippingAddress): void |
||
103 | |||
104 | public function selectShippingAddressProvince(string $province): void |
||
109 | |||
110 | public function specifyBillingAddress(AddressInterface $billingAddress): void |
||
114 | |||
115 | public function selectBillingAddressProvince(string $province): void |
||
120 | |||
121 | public function specifyEmail(?string $email): void |
||
125 | |||
126 | public function specifyBillingAddressFullName(string $fullName): void |
||
127 | { |
||
128 | $names = explode(' ', $fullName); |
||
129 | |||
130 | $this->getElement('billing_first_name')->setValue($names[0]); |
||
131 | $this->getElement('billing_last_name')->setValue($names[1]); |
||
132 | } |
||
133 | |||
134 | public function canSignIn(): bool |
||
138 | |||
139 | public function signIn(): void |
||
151 | |||
152 | public function specifyPassword(string $password): void |
||
160 | |||
161 | public function getItemSubtotal(string $itemName): string |
||
169 | |||
170 | public function getShippingAddressCountry(): string |
||
174 | |||
175 | public function nextStep(): void |
||
179 | |||
180 | public function backToStore(): void |
||
184 | |||
185 | public function specifyBillingAddressProvince(string $provinceName): void |
||
190 | |||
191 | public function specifyShippingAddressProvince(string $provinceName): void |
||
196 | |||
197 | public function hasShippingAddressInput(): bool |
||
201 | |||
202 | public function hasBillingAddressInput(): bool |
||
206 | |||
207 | public function selectShippingAddressFromAddressBook(AddressInterface $address): void |
||
208 | { |
||
209 | $this->waitForElement(2, sprintf('%s_province', self::TYPE_SHIPPING)); |
||
210 | $addressBookSelect = $this->getElement('shipping_address_book'); |
||
211 | |||
212 | $addressBookSelect->click(); |
||
213 | $addressOption = $addressBookSelect->waitFor(5, function () use ($address, $addressBookSelect) { |
||
214 | return $addressBookSelect->find('css', sprintf('.item[data-id="%s"]', $address->getId())); |
||
215 | }); |
||
216 | |||
217 | if (null === $addressOption) { |
||
218 | throw new ElementNotFoundException($this->getDriver(), 'option', 'css', sprintf('.item[data-id="%s"]', $address->getId())); |
||
219 | } |
||
220 | |||
221 | $addressOption->click(); |
||
222 | } |
||
223 | |||
224 | public function selectBillingAddressFromAddressBook(AddressInterface $address): void |
||
225 | { |
||
226 | $this->waitForElement(2, sprintf('%s_province', self::TYPE_BILLING)); |
||
227 | $addressBookSelect = $this->getElement('billing_address_book'); |
||
228 | |||
229 | $addressBookSelect->click(); |
||
230 | $addressOption = $addressBookSelect->waitFor(5, function () use ($address, $addressBookSelect) { |
||
231 | return $addressBookSelect->find('css', sprintf('.item[data-id="%s"]', $address->getId())); |
||
232 | }); |
||
233 | |||
234 | if (null === $addressOption) { |
||
235 | throw new ElementNotFoundException($this->getDriver(), 'option', 'css', sprintf('.item[data-id="%s"]', $address->getId())); |
||
236 | } |
||
237 | |||
238 | $addressOption->click(); |
||
239 | |||
240 | JQueryHelper::waitForFormToStopLoading($this->getDocument()); |
||
241 | } |
||
242 | |||
243 | public function getPreFilledShippingAddress(): AddressInterface |
||
247 | |||
248 | public function getPreFilledBillingAddress(): AddressInterface |
||
252 | |||
253 | protected function getDefinedElements(): array |
||
254 | { |
||
255 | return array_merge(parent::getDefinedElements(), [ |
||
256 | 'billing_address_book' => '[data-test-billing-address] [data-test-address-book]', |
||
285 | |||
286 | private function getPreFilledAddress(string $type): AddressInterface |
||
309 | |||
310 | private function specifyAddress(AddressInterface $address, string $type): void |
||
332 | |||
333 | private function getFieldElement(string $element): ?NodeElement |
||
342 | |||
343 | private function waitForLoginAction(): bool |
||
349 | |||
350 | private function waitForElement(int $timeout, string $elementName): bool |
||
356 | |||
357 | private function assertAddressType(string $type): void |
||
363 | } |
||
364 |
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.