Skip to content

Commit 016d7ef

Browse files
Gregcop1dunglas
andauthored
feat: add future assertion (#411)
* feat: add future assertion * Update README.md Co-authored-by: Kévin Dunglas <[email protected]> * Update README.md Co-authored-by: Kévin Dunglas <[email protected]> * Update README.md Co-authored-by: Kévin Dunglas <[email protected]> * Update README.md Co-authored-by: Kévin Dunglas <[email protected]> * Update src/WebDriver/PantherWebDriverExpectedCondition.php Co-authored-by: Kévin Dunglas <[email protected]> * fix: @dunglas && @chalasr review Co-authored-by: Kévin Dunglas <[email protected]>
1 parent cd7501b commit 016d7ef

13 files changed

+466
-17
lines changed

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,32 @@ class E2eTest extends PantherTestCase
159159
$this->assertSelectorIsDisabled('[type="submit"]');
160160
$this->assertSelectorIsVisible('.errors');
161161
$this->assertSelectorIsNotVisible('.loading');
162+
$this->assertSelectorAttributeContains('.price', 'data-old-price', '42');
163+
$this->assertSelectorAttributeNotContains('.price', 'data-old-price', '36');
162164

163165
// Use waitForX methods to wait until some asynchronous process finish
164-
$client->waitFor('.popin'); // element is attached to the DOM
165-
$client->waitForStaleness('.popin'); // element is removed from the DOM
166-
$client->waitForVisibility('.loader'); // element of the DOM becomes visible
167-
$client->waitForInvisibility('.loader'); // element of the DOM becomes hidden
168-
$client->waitForElementToContain('.total', '25 €'); // text is inserted in the element content
169-
$client->waitForElementToNotContain('.promotion', '5%'); // text is removed from the element content
170-
166+
$client->waitFor('.popin'); // wait for element to be attached to the DOM
167+
$client->waitForStaleness('.popin'); // wait for element to be removed from the DOM
168+
$client->waitForVisibility('.loader'); // wait for element of the DOM to become visible
169+
$client->waitForInvisibility('.loader'); // wait for element of the DOM to become hidden
170+
$client->waitForElementToContain('.total', '25 €'); // wait for text to be inserted in the element content
171+
$client->waitForElementToNotContain('.promotion', '5%'); // wait for text to be removed from the element content
172+
$client->waitForEnabled('[type="submit"]'); // wait for the button to become enabled
173+
$client->waitForDisabled('[type="submit"]'); // wait for the button to become disabled
174+
$client->waitForAttributeToContain('.price', 'data-old-price', '25 €'); // wait for the attribute to contain content
175+
$client->waitForAttributeToNotContain('.price', 'data-old-price', '25 €'); // wait for the attribute to not contain content
176+
177+
// Let's predict the future
178+
$this->assertSelectorWillExist('.popin'); // element will be attached to the DOM
179+
$this->assertSelectorWillNotExist('.popin'); // element will be removed from the DOM
180+
$this->assertSelectorWillBeVisible('.loader'); // element will be visible
181+
$this->assertSelectorWillNotBeVisible('.loader'); // element will be visible
182+
$this->assertSelectorWillContain('.total', '€25'); // text will be inserted in the element content
183+
$this->assertSelectorWillNotContain('.promotion', '5%'); // text will be removed from the element content
184+
$this->assertSelectorWillBeEnabled('[type="submit"]'); // button will be enabled
185+
$this->assertSelectorWillBeDisabled('[type="submit"]'); // button will be disabled
186+
$this->assertSelectorAttributeWillContain('.price', 'data-old-price', '€25'); // attribute will contains content
187+
$this->assertSelectorAttributeWillNotContain('.price', 'data-old-price', '€25'); // attribute will not contain content
171188
}
172189
}
173190
```

src/Client.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,50 @@ public function waitForElementToNotContain(string $locator, string $text, int $t
426426
return $this->crawler = $this->createCrawler();
427427
}
428428

429+
public function waitForAttributeToContain(string $locator, string $attribute, string $text, int $timeoutInSecond = 30, int $intervalInMillisecond = 250)
430+
{
431+
$by = self::createWebDriverByFromLocator($locator);
432+
433+
$this->wait($timeoutInSecond, $intervalInMillisecond)->until(
434+
PantherWebDriverExpectedCondition::elementAttributeContains($by, $attribute, $text)
435+
);
436+
437+
return $this->crawler = $this->createCrawler();
438+
}
439+
440+
public function waitForAttributeToNotContain(string $locator, string $attribute, string $text, int $timeoutInSecond = 30, int $intervalInMillisecond = 250)
441+
{
442+
$by = self::createWebDriverByFromLocator($locator);
443+
444+
$this->wait($timeoutInSecond, $intervalInMillisecond)->until(
445+
PantherWebDriverExpectedCondition::elementAttributeNotContains($by, $attribute, $text)
446+
);
447+
448+
return $this->crawler = $this->createCrawler();
449+
}
450+
451+
public function waitForEnabled(string $locator, int $timeoutInSecond = 30, int $intervalInMillisecond = 250)
452+
{
453+
$by = self::createWebDriverByFromLocator($locator);
454+
455+
$this->wait($timeoutInSecond, $intervalInMillisecond)->until(
456+
PantherWebDriverExpectedCondition::elementEnabled($by)
457+
);
458+
459+
return $this->crawler = $this->createCrawler();
460+
}
461+
462+
public function waitForDisabled(string $locator, int $timeoutInSecond = 30, int $intervalInMillisecond = 250)
463+
{
464+
$by = self::createWebDriverByFromLocator($locator);
465+
466+
$this->wait($timeoutInSecond, $intervalInMillisecond)->until(
467+
PantherWebDriverExpectedCondition::elementDisabled($by)
468+
);
469+
470+
return $this->crawler = $this->createCrawler();
471+
}
472+
429473
public function getWebDriver(): WebDriver
430474
{
431475
$this->start();

src/WebDriver/PantherWebDriverExpectedCondition.php

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,61 @@ public static function elementTextNotContains(WebDriverBy $by, string $text): ca
2323
{
2424
return static function (WebDriver $driver) use ($by, $text) {
2525
try {
26-
$element_text = $driver->findElement($by)->getText();
26+
$elementText = $driver->findElement($by)->getText();
2727

28-
return false === strpos($element_text, $text);
28+
return false === strpos($elementText, $text);
29+
} catch (StaleElementReferenceException $e) {
30+
return null;
31+
}
32+
}
33+
;
34+
}
35+
36+
public static function elementEnabled(WebDriverBy $by)
37+
{
38+
return static function (WebDriver $driver) use ($by) {
39+
try {
40+
return $driver->findElement($by)->isEnabled();
41+
} catch (StaleElementReferenceException $e) {
42+
return null;
43+
}
44+
}
45+
;
46+
}
47+
48+
public static function elementDisabled(WebDriverBy $by)
49+
{
50+
return static function (WebDriver $driver) use ($by) {
51+
try {
52+
return !$driver->findElement($by)->isEnabled();
53+
} catch (StaleElementReferenceException $e) {
54+
return null;
55+
}
56+
}
57+
;
58+
}
59+
60+
public static function elementAttributeContains(WebDriverBy $by, string $attribute, string $text)
61+
{
62+
return static function (WebDriver $driver) use ($by, $attribute, $text) {
63+
try {
64+
$attributeValue = $driver->findElement($by)->getAttribute($attribute);
65+
66+
return null !== $attributeValue && false !== strpos($attributeValue, $text);
67+
} catch (StaleElementReferenceException $e) {
68+
return null;
69+
}
70+
}
71+
;
72+
}
73+
74+
public static function elementAttributeNotContains(WebDriverBy $by, string $attribute, string $text)
75+
{
76+
return static function (WebDriver $driver) use ($by, $attribute, $text) {
77+
try {
78+
$attributeValue = $driver->findElement($by)->getAttribute($attribute);
79+
80+
return null !== $attributeValue && false === strpos($attributeValue, $text);
2981
} catch (StaleElementReferenceException $e) {
3082
return null;
3183
}

src/WebTestAssertionsTrait.php

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,37 @@ trait WebTestAssertionsTrait
3333
}
3434
use PantherTestCaseTrait;
3535

36+
/** @TODO replace this after patching Symfony to allow xpath selectors */
37+
public static function assertSelectorExists(string $selector, string $message = ''): void
38+
{
39+
$element = self::findElement($selector);
40+
self::assertNotNull($element, $message);
41+
}
42+
43+
/** @TODO replace this after patching Symfony to allow xpath selectors */
44+
public static function assertSelectorNotExists(string $selector, string $message = ''): void
45+
{
46+
/** @var PantherClient $client */
47+
$client = self::getClient();
48+
$by = $client::createWebDriverByFromLocator($selector);
49+
$elements = $client->findElements($by);
50+
self::assertEmpty($elements, $message);
51+
}
52+
53+
/** @TODO replace this after patching Symfony to allow xpath selectors */
54+
public static function assertSelectorTextContains(string $selector, string $text, string $message = ''): void
55+
{
56+
$element = self::findElement($selector);
57+
self::assertStringContainsString($text, $element->getText(), $message);
58+
}
59+
60+
/** @TODO replace this after patching Symfony to allow xpath selectors */
61+
public static function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void
62+
{
63+
$element = self::findElement($selector);
64+
self::assertStringNotContainsString($text, $element->getText(), $message);
65+
}
66+
3667
public static function assertPageTitleSame(string $expectedTitle, string $message = ''): void
3768
{
3869
$client = self::getClient();
@@ -63,30 +94,129 @@ public static function assertPageTitleContains(string $expectedTitle, string $me
6394
self::baseAssertPageTitleContains($expectedTitle, $message);
6495
}
6596

97+
public static function assertSelectorWillExist(string $locator): void
98+
{
99+
/** @var PantherClient $client */
100+
$client = self::getClient();
101+
$client->waitFor($locator);
102+
self::assertSelectorExists($locator);
103+
}
104+
105+
public static function assertSelectorWillNotExist(string $locator): void
106+
{
107+
/** @var PantherClient $client */
108+
$client = self::getClient();
109+
$client->waitForStaleness($locator);
110+
self::assertSelectorNotExists($locator);
111+
}
112+
66113
public static function assertSelectorIsVisible(string $locator): void
67114
{
68115
$element = self::findElement($locator);
69116
self::assertTrue($element->isDisplayed(), 'Failed asserting that element is visible.');
70117
}
71118

119+
public static function assertSelectorWillBeVisible(string $locator): void
120+
{
121+
/** @var PantherClient $client */
122+
$client = self::getClient();
123+
$client->waitForVisibility($locator);
124+
self::assertSelectorIsVisible($locator);
125+
}
126+
72127
public static function assertSelectorIsNotVisible(string $locator): void
73128
{
74129
$element = self::findElement($locator);
75130
self::assertFalse($element->isDisplayed(), 'Failed asserting that element is not visible.');
76131
}
77132

133+
public static function assertSelectorWillNotBeVisible(string $locator): void
134+
{
135+
/** @var PantherClient $client */
136+
$client = self::getClient();
137+
$client->waitForInvisibility($locator);
138+
self::assertSelectorIsNotVisible($locator);
139+
}
140+
141+
public static function assertSelectorWillContain(string $locator, string $text): void
142+
{
143+
/** @var PantherClient $client */
144+
$client = self::getClient();
145+
$client->waitForElementToContain($locator, $text);
146+
self::assertSelectorTextContains($locator, $text);
147+
}
148+
149+
public static function assertSelectorWillNotContain(string $locator, string $text): void
150+
{
151+
/** @var PantherClient $client */
152+
$client = self::getClient();
153+
$client->waitForElementToNotContain($locator, $text);
154+
self::assertSelectorTextNotContains($locator, $text);
155+
}
156+
78157
public static function assertSelectorIsEnabled(string $locator): void
79158
{
80159
$element = self::findElement($locator);
81160
self::assertTrue($element->isEnabled(), 'Failed asserting that element is enabled.');
82161
}
83162

163+
public static function assertSelectorWillBeEnabled(string $locator): void
164+
{
165+
/** @var PantherClient $client */
166+
$client = self::getClient();
167+
$client->waitForEnabled($locator);
168+
self::assertSelectorAttributeContains($locator, 'disabled');
169+
}
170+
84171
public static function assertSelectorIsDisabled(string $locator): void
85172
{
86173
$element = self::findElement($locator);
87174
self::assertFalse($element->isEnabled(), 'Failed asserting that element is disabled.');
88175
}
89176

177+
public static function assertSelectorWillBeDisabled(string $locator): void
178+
{
179+
/** @var PantherClient $client */
180+
$client = self::getClient();
181+
$client->waitForDisabled($locator);
182+
self::assertSelectorAttributeContains($locator, 'disabled', 'true');
183+
}
184+
185+
public static function assertSelectorAttributeContains(string $locator, string $attribute, string $text = null): void
186+
{
187+
$element = self::findElement($locator);
188+
189+
if (null === $text) {
190+
self::assertNull($element->getAttribute($attribute));
191+
192+
return;
193+
}
194+
195+
self::assertStringContainsString($text, $element->getAttribute($attribute));
196+
}
197+
198+
public static function assertSelectorAttributeWillContain(string $locator, string $attribute, string $text): void
199+
{
200+
/** @var PantherClient $client */
201+
$client = self::getClient();
202+
$client->waitForAttributeToContain($locator, $attribute, $text);
203+
self::assertSelectorAttributeContains($locator, $attribute, $text);
204+
}
205+
206+
public static function assertSelectorAttributeNotContains(string $locator, string $attribute, string $text): void
207+
{
208+
$element = self::findElement($locator);
209+
self::assertStringNotContainsString($text, $element->getAttribute($attribute));
210+
}
211+
212+
public static function assertSelectorAttributeWillNotContain(string $locator, string $attribute, string $text): void
213+
{
214+
/** @var PantherClient $client */
215+
$client = self::getClient();
216+
$client->waitForAttributeToNotContain($locator, $attribute, $text);
217+
self::assertSelectorAttributeNotContains($locator, $attribute, $text);
218+
}
219+
90220
private static function findElement(string $locator): WebDriverElement
91221
{
92222
/** @var PantherClient $client */

tests/AssertionsTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public function testDomCrawlerAssertions(): void
4343
$this->assertInputValueSame('in', 'test');
4444
$this->assertSelectorIsVisible('.p-1');
4545
$this->assertSelectorIsEnabled('[name="in"]');
46+
$this->assertSelectorAttributeContains('.price', 'data-old-price', '42');
47+
$this->assertSelectorAttributeNotContains('.price', 'data-old-price', '36');
4648
self::createPantherClient()->request('GET', '/input-disabled.html');
4749
$this->assertSelectorIsDisabled('[name="in-disabled"]');
4850
self::createPantherClient()->request('GET', '/text-hidden.html');

tests/ClientTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,54 @@ public function testWaitForElementToNotContain(string $locator)
125125
$this->assertSame('Hello', $crawler->filter('#hello')->text());
126126
}
127127

128+
/**
129+
* @dataProvider waitForDataProvider
130+
*/
131+
public function testWaitForEnabled(string $locator)
132+
{
133+
$client = self::createPantherClient();
134+
$client->request('GET', '/waitfor-input-to-be-enabled.html');
135+
$crawler = $client->waitForEnabled($locator);
136+
$this->assertInstanceOf(Crawler::class, $crawler);
137+
$this->assertTrue($crawler->filter('#hello')->isEnabled());
138+
}
139+
140+
/**
141+
* @dataProvider waitForDataProvider
142+
*/
143+
public function testWaitForDisabled(string $locator)
144+
{
145+
$client = self::createPantherClient();
146+
$client->request('GET', '/waitfor-input-to-be-disabled.html');
147+
$crawler = $client->waitForDisabled($locator);
148+
$this->assertInstanceOf(Crawler::class, $crawler);
149+
$this->assertFalse($crawler->filter('#hello')->isEnabled());
150+
}
151+
152+
/**
153+
* @dataProvider waitForDataProvider
154+
*/
155+
public function testWaitForAttributeToContain(string $locator)
156+
{
157+
$client = self::createPantherClient();
158+
$crawler = $client->request('GET', '/waitfor-attribute-to-contain.html');
159+
$c = $client->waitForAttributeToContain($locator, 'data-old-price', '42');
160+
$this->assertInstanceOf(Crawler::class, $c);
161+
$this->assertSame('42', $crawler->filter('#hello')->getAttribute('data-old-price'));
162+
}
163+
164+
/**
165+
* @dataProvider waitForDataProvider
166+
*/
167+
public function testWaitForAttributeToNotContain(string $locator)
168+
{
169+
$client = self::createPantherClient();
170+
$client->request('GET', '/waitfor-attribute-to-contain.html');
171+
$crawler = $client->waitForAttributeToContain($locator, 'data-old-price', '36');
172+
$this->assertInstanceOf(Crawler::class, $crawler);
173+
$this->assertSame('36', $crawler->filter('#hello')->getAttribute('data-old-price'));
174+
}
175+
128176
/**
129177
* @dataProvider waitForDataProvider
130178
*/

0 commit comments

Comments
 (0)