Skip to content

Commit b00ecfa

Browse files
authored
Backported ElementTransitionHasEndedCondition (#283)
1 parent 85edfa9 commit b00ecfa

11 files changed

+193
-78
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,26 @@
11
const path = require('path');
22

33
module.exports = (eZConfig, eZConfigManager) => {
4+
const addEntry = ([entryName, newItems]) => {
5+
if (eZConfig.entry[entryName]) {
6+
eZConfigManager.add({
7+
eZConfig,
8+
entryName,
9+
newItems,
10+
});
11+
}
12+
};
13+
const seleniumDebugStylePath = path.resolve(__dirname, '../public/css/selenium-debug.css');
14+
const dragMockScriptPath = path.resolve(__dirname, '../public/js/scripts/drag-mock.js');
15+
const transitionListenerScriptPath = path.resolve(__dirname, '../public/js/scripts/transition-listener.js');
16+
const scriptsMap = {
17+
'ezplatform-admin-ui-layout-css': [seleniumDebugStylePath],
18+
'ezplatform-admin-ui-security-base-css': [seleniumDebugStylePath],
19+
'ezplatform-page-builder-edit-js': [dragMockScriptPath],
20+
'ezplatform-form-builder-common-js': [dragMockScriptPath],
21+
'ezcommerce-shop-pagelayout-css': [seleniumDebugStylePath],
22+
'ezplatform-admin-ui-layout-js': [transitionListenerScriptPath],
23+
};
424

5-
const dragMockScriptPath = '../public/js/scripts/drag-mock.js';
6-
const seleniumDebugStylePath = '../public/css/selenium-debug.css';
7-
8-
eZConfigManager.add({
9-
eZConfig,
10-
entryName: 'ezplatform-admin-ui-layout-css',
11-
newItems: [
12-
path.resolve(__dirname, seleniumDebugStylePath)
13-
]
14-
});
15-
16-
eZConfigManager.add({
17-
eZConfig,
18-
entryName: 'ezplatform-admin-ui-security-base-css',
19-
newItems: [
20-
path.resolve(__dirname, seleniumDebugStylePath)
21-
]
22-
});
23-
24-
if (eZConfig.entry['ezplatform-page-builder-edit-js']) {
25-
const dragMockScriptPath = '../public/js/scripts/drag-mock.js';
26-
eZConfigManager.add({
27-
eZConfig,
28-
entryName: 'ezplatform-page-builder-edit-js',
29-
newItems: [
30-
path.resolve(__dirname, dragMockScriptPath),
31-
],
32-
});
33-
}
34-
35-
if (eZConfig.entry['ezplatform-form-builder-common-js']) {
36-
eZConfigManager.add({
37-
eZConfig,
38-
entryName: 'ezplatform-form-builder-common-js',
39-
newItems: [
40-
path.resolve(__dirname, dragMockScriptPath),
41-
],
42-
});
43-
}
44-
45-
if (eZConfig.entry['ezcommerce-shop-pagelayout-css']) {
46-
eZConfigManager.add({
47-
eZConfig,
48-
entryName: 'ezcommerce-shop-pagelayout-css',
49-
newItems: [
50-
path.resolve(__dirname, seleniumDebugStylePath)
51-
]
52-
});
53-
}
25+
Object.entries(scriptsMap).forEach(addEntry);
5426
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const transitionEndedClass = 'ibexa-selenium-transition-ended';
2+
const transitionStartedClass = 'ibexa-selenium-transition-started';
3+
document.addEventListener('transitionstart', (event) => {
4+
event.target.classList.add(transitionStartedClass)
5+
event.target.classList.remove(transitionEndedClass)
6+
});
7+
document.addEventListener('transitionend', (event) => {
8+
event.target.classList.add(transitionEndedClass)
9+
event.target.classList.remove(transitionStartedClass)
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Behat\Browser\Element\Condition;
10+
11+
use Ibexa\Behat\Browser\Element\BaseElementInterface;
12+
use Ibexa\Behat\Browser\Locator\LocatorInterface;
13+
14+
class ElementTransitionHasEndedCondition implements ConditionInterface
15+
{
16+
private const TRANSITION_ENDED_CLASS = 'ibexa-selenium-transition-ended';
17+
18+
private const TRANSITION_STARTED_CLASS = 'ibexa-selenium-transition-started';
19+
20+
/** @var \Ibexa\Behat\Browser\Locator\LocatorInterface */
21+
private $elementLocator;
22+
23+
/** @var \Ibexa\Behat\Browser\Element\BaseElementInterface */
24+
private $searchedNode;
25+
26+
/** @var bool */
27+
private $hasStartedTransitioning;
28+
29+
public function __construct(BaseElementInterface $searchedNode, LocatorInterface $elementLocator)
30+
{
31+
$this->elementLocator = $elementLocator;
32+
$this->searchedNode = $searchedNode;
33+
}
34+
35+
public function isMet(): bool
36+
{
37+
$currentTimeout = $this->searchedNode->getTimeout();
38+
$this->searchedNode->setTimeout(0);
39+
40+
$this->hasStartedTransitioning = $this->searchedNode->find($this->elementLocator)->hasClass(self::TRANSITION_STARTED_CLASS);
41+
$hasTransitionEndedClass = $this->searchedNode->find($this->elementLocator)->hasClass(self::TRANSITION_ENDED_CLASS);
42+
$this->searchedNode->setTimeout($currentTimeout);
43+
44+
return $hasTransitionEndedClass;
45+
}
46+
47+
public function getErrorMessage(BaseElementInterface $invokingElement): string
48+
{
49+
return $this->hasStartedTransitioning ?
50+
sprintf(
51+
"Transition has not ended for element with %s locator '%s': '%s'. Timeout value: %d seconds.",
52+
strtoupper($this->elementLocator->getType()),
53+
$this->elementLocator->getIdentifier(),
54+
$this->elementLocator->getSelector(),
55+
$invokingElement->getTimeout()
56+
)
57+
:
58+
sprintf(
59+
"Transition has not started at all for element with %s locator '%s': '%s'. Please make sure the condition is used on the correct element. Timeout value: %d seconds.",
60+
strtoupper($this->elementLocator->getType()),
61+
$this->elementLocator->getIdentifier(),
62+
$this->elementLocator->getSelector(),
63+
$invokingElement->getTimeout()
64+
);
65+
}
66+
}

src/lib/Browser/Element/Debug/Highlighting/BaseElement.php

-11
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,6 @@ private function addClass(ElementInterface $element, string $class): void
9898
);
9999
}
100100

101-
protected function removeClass(ElementInterface $element, string $class): void
102-
{
103-
$this->session->executeScript(
104-
sprintf(
105-
"%s.classList.remove('%s')",
106-
$this->getElementScript($element),
107-
$class
108-
)
109-
);
110-
}
111-
112101
protected function markRead(ElementInterface $element): void
113102
{
114103
$this->addClass($element, self::READ_CLASS);

tests/Browser/Element/BaseTestCase.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,26 @@ protected function createElement(string $elementText): ElementInterface
3636
return $element;
3737
}
3838

39-
protected function createElementWithChildElement(string $elementText, LocatorInterface $childLocator, string $childElementText): ElementInterface
39+
protected function createElementWithChildElement(string $elementText, LocatorInterface $childLocator, ElementInterface $childElement): ElementInterface
4040
{
4141
$element = $this->createMock(ElementInterface::class);
4242
$element->method('getText')->willReturn($elementText);
4343
$element->method('getTimeout')->willReturn(1);
44-
$element->method('find')->willReturnCallback(function () use ($childLocator, $childElementText) {
44+
$element->method('find')->willReturnCallback(static function () use ($childLocator, $childElement) {
4545
/** @var \Ibexa\Behat\Browser\Locator\LocatorInterface $locator */
4646
$locator = func_get_args()[0];
4747
if ($locator == $childLocator) {
48-
return $this->createElement($childElementText);
48+
return $childElement;
4949
}
5050

5151
throw new TimeoutException();
5252
});
5353

54-
$element->method('findAll')->willReturnCallback(function () use ($childLocator, $childElementText) {
54+
$element->method('findAll')->willReturnCallback(function () use ($childLocator, $childElement) {
5555
/** @var \Ibexa\Behat\Browser\Locator\LocatorInterface $locator */
5656
$locator = func_get_args()[0];
5757
if ($locator == $childLocator) {
58-
return $this->createCollection($childLocator, $childElementText);
58+
return $this->createCollection($childLocator, $childElement->getText());
5959
}
6060

6161
return $this->createCollection($childLocator);

tests/Browser/Element/Condition/ElementExistsConditionTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function testElementExists(): void
1919
{
2020
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
2121
$condition = new ElementExistsCondition(
22-
$this->createElementWithChildElement('root', $searchedElementLocator, 'ChildText'),
22+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText')),
2323
$searchedElementLocator
2424
);
2525

@@ -29,7 +29,7 @@ public function testElementExists(): void
2929
public function testElementDoesNotExist(): void
3030
{
3131
$condition = new ElementExistsCondition(
32-
$this->createElementWithChildElement('root', new CSSLocator('irrelevant-id', 'irrelevant-child'), 'ChildText'),
32+
$this->createElementWithChildElement('root', new CSSLocator('irrelevant-id', 'irrelevant-child'), $this->createElement('ChildText')),
3333
new CSSLocator('searched-id', 'searched-test')
3434
);
3535

tests/Browser/Element/Condition/ElementNotExistsConditionTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function testElementDoesNotExist(): void
2020
$searchedElementLocator = new CSSLocator('not-exist-id', 'not-exist-selector');
2121
$condition = new ElementNotExistsCondition(
2222
$this->createElementWithChildElement(
23-
'root', new CSSLocator('dummy-id', 'dummy-selector'), 'DummyText',
23+
'root', new CSSLocator('dummy-id', 'dummy-selector'), $this->createElement('DummyText'),
2424
),
2525
$searchedElementLocator
2626
);
@@ -32,7 +32,7 @@ public function testElementExist(): void
3232
{
3333
$shouldNotExistLocator = new CSSLocator('should-not-exist-id', 'should-not-exist-selector');
3434
$condition = new ElementNotExistsCondition(
35-
$this->createElementWithChildElement('root', $shouldNotExistLocator, 'ChildText'),
35+
$this->createElementWithChildElement('root', $shouldNotExistLocator, $this->createElement('ChildText')),
3636
$shouldNotExistLocator
3737
);
3838
$invokingElement = $this->createElement('Test');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace EzSystems\Behat\Test\Browser\Element\Condition;
10+
11+
use EzSystems\Behat\Test\Browser\Element\BaseTestCase;
12+
use Ibexa\Behat\Browser\Element\Condition\ElementTransitionHasEndedCondition;
13+
use Ibexa\Behat\Browser\Element\ElementInterface;
14+
use Ibexa\Behat\Browser\Locator\CSSLocator;
15+
use PHPUnit\Framework\Assert;
16+
17+
class ElementTransitionHasEndedConditionTest extends BaseTestCase
18+
{
19+
public function testElementTransitionHasEnded(): void
20+
{
21+
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
22+
23+
$condition = new ElementTransitionHasEndedCondition(
24+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createChildElement(false, true)),
25+
$searchedElementLocator
26+
);
27+
28+
Assert::assertTrue($condition->isMet());
29+
}
30+
31+
public function testElementTransitionHasNotEndedInTime(): void
32+
{
33+
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
34+
$baseElement = $this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText'));
35+
36+
$condition = new ElementTransitionHasEndedCondition(
37+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createChildElement(true, false)),
38+
$searchedElementLocator
39+
);
40+
41+
Assert::assertFalse($condition->isMet());
42+
Assert::assertEquals(
43+
"Transition has not ended for element with CSS locator 'searched-id': 'searched-test'. Timeout value: 1 seconds.",
44+
$condition->getErrorMessage($baseElement)
45+
);
46+
}
47+
48+
public function testElementTransitionHasNotStarted(): void
49+
{
50+
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
51+
$baseElement = $this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText'));
52+
53+
$condition = new ElementTransitionHasEndedCondition(
54+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createChildElement(false, false)),
55+
$searchedElementLocator
56+
);
57+
58+
Assert::assertFalse($condition->isMet());
59+
Assert::assertEquals(
60+
"Transition has not started at all for element with CSS locator 'searched-id': 'searched-test'. Please make sure the condition is used on the correct element. Timeout value: 1 seconds.",
61+
$condition->getErrorMessage($baseElement)
62+
);
63+
}
64+
65+
private function createChildElement(bool $hasStartedTransition, bool $hasEndedTransition): ElementInterface
66+
{
67+
$childElement = $this->createStub(ElementInterface::class);
68+
$childElement->method('getText')->willReturn('ChildText');
69+
$childElement->method('hasClass')->will($this->returnValueMap(
70+
[
71+
['ibexa-selenium-transition-started', $hasStartedTransition],
72+
['ibexa-selenium-transition-ended', $hasEndedTransition],
73+
]
74+
));
75+
76+
return $childElement;
77+
}
78+
}

tests/Browser/Element/Condition/ElementsCountConditionTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function testExpectedCountPresent(): void
1919
{
2020
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
2121
$condition = new ElementsCountCondition(
22-
$this->createElementWithChildElement('root', $searchedElementLocator, 'ChildText'),
22+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText')),
2323
$searchedElementLocator,
2424
1
2525
);
@@ -31,7 +31,7 @@ public function testExpectedCountNotPresent(): void
3131
{
3232
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
3333
$condition = new ElementsCountCondition(
34-
$this->createElementWithChildElement('root', $searchedElementLocator, 'ChildText'),
34+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText')),
3535
$searchedElementLocator,
3636
0
3737
);

tests/Browser/Element/Condition/ElementsCountGreaterThanConditionTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function testExpectedCountPresent(): void
1919
{
2020
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
2121
$condition = new ElementsCountGreaterThanCondition(
22-
$this->createElementWithChildElement('root', $searchedElementLocator, 'ChildText'),
22+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText')),
2323
$searchedElementLocator,
2424
0
2525
);
@@ -31,7 +31,7 @@ public function testExpectedCountNotPresent(): void
3131
{
3232
$searchedElementLocator = new CSSLocator('searched-id', 'searched-test');
3333
$condition = new ElementsCountGreaterThanCondition(
34-
$this->createElementWithChildElement('root', $searchedElementLocator, 'ChildText'),
34+
$this->createElementWithChildElement('root', $searchedElementLocator, $this->createElement('ChildText')),
3535
$searchedElementLocator,
3636
1
3737
);

tests/Browser/Element/Criterion/ChildElementTextCriterionTest.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ public function testMatches(ElementInterface $element, bool $shouldMatch): void
3030
public function dataProviderTestMatches(): array
3131
{
3232
return [
33-
[$this->createElementWithChildElement('ignore', new XPathLocator('id', 'selector'), 'expectedChildText'), true],
34-
[$this->createElementWithChildElement('ignore', new XPathLocator('id', 'selector'), 'notExpectedChildText'), false],
35-
[$this->createElementWithChildElement('ignore', new XPathLocator('id', 'invalidSelector'), 'expectedChildText'), false],
33+
[$this->createElementWithChildElement('ignore', new XPathLocator('id', 'selector'), $this->createElement('expectedChildText')), true],
34+
[$this->createElementWithChildElement('ignore', new XPathLocator('id', 'selector'), $this->createElement('notExpectedChildText')), false],
35+
[$this->createElementWithChildElement('ignore', new XPathLocator('id', 'invalidSelector'), $this->createElement('expectedChildText')), false],
3636
];
3737
}
3838

3939
public function testGetErrorMessageWhenNoElementFound(): void
4040
{
4141
$childLocator = new XPathLocator('id', 'child-selector');
4242
$criterion = new ChildElementTextCriterion($childLocator, 'expectedChildText');
43-
$invalidElement = $this->createElementWithChildElement('ignore', $childLocator, 'expectedChildText');
43+
$invalidElement = $this->createElementWithChildElement('ignore', $childLocator, $this->createElement('expectedChildText'));
4444
$criterion->matches($invalidElement);
4545

4646
Assert::assertEquals(
@@ -56,7 +56,7 @@ public function testGetErrorMessageWhenOtherElementFound(): void
5656
{
5757
$childLocator = new XPathLocator('id', 'child-selector');
5858
$criterion = new ChildElementTextCriterion($childLocator, 'expectedChildText');
59-
$invalidElement = $this->createElementWithChildElement('ignore', $childLocator, 'notExpectedChildText');
59+
$invalidElement = $this->createElementWithChildElement('ignore', $childLocator, $this->createElement('notExpectedChildText'));
6060
$criterion->matches($invalidElement);
6161

6262
Assert::assertEquals(

0 commit comments

Comments
 (0)