Completed
Pull Request — master (#441)
by Michael
02:18
created

FixtureContext::stepISelectGalleryItem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
1
<?php
2
3
namespace SilverStripe\AssetAdmin\Tests\Behat\Context;
4
5
use Behat\Mink\Element\DocumentElement;
6
use Behat\Mink\Element\NodeElement;
7
use Page;
8
use SilverStripe\Assets\Image;
9
use SilverStripe\BehatExtension\Context\FixtureContext as BaseFixtureContext;
10
11
/**
12
 * Context used to create fixtures in the SilverStripe ORM.
13
 */
14
class FixtureContext extends BaseFixtureContext
15
{
16
17
    /**
18
     * Select a gallery item by type and name
19
     *
20
     * @Given /^I (?:(?:click on)|(?:select)) the file named "([^"]+)" in the gallery$/
21
     * @param string $name
22
     */
23
    public function stepISelectGalleryItem($name)
24
    {
25
        $item = $this->getGalleryItem($name);
26
        assertNotNull($item, "File named $name could not be found");
27
        $item->click();
28
    }
29
30
    /**
31
     * Check the checkbox for a given gallery item
32
     * @Given /^I check the file named "([^"]+)" in the gallery$/
33
     * @param string $name
34
     */
35
    public function stepICheckTheGalleryItem($name)
36
    {
37
        $item = $this->getGalleryItem($name);
38
        assertNotNull($item, "File named $name could not be found");
39
        $checkbox = $item->find('css', 'input[type="checkbox"]');
40
        assertNotNull($checkbox, "Could not find checkbox for file named {$name}");
41
        $checkbox->check();
42
    }
43
44
    /**
45
     * @Then /^I should see the file named "([^"]+)" in the gallery$/
46
     * @param string $name
47
     */
48
    public function iShouldSeeTheGalleryItem($name)
49
    {
50
        $item = $this->getGalleryItem($name);
51
        assertNotNull($item, "File named {$name} could not be found");
52
    }
53
54
    /**
55
     * @Then /^I should not see the file named "([^"]+)" in the gallery$/
56
     * @param string $name
57
     */
58
    public function iShouldNotSeeTheGalleryItem($name)
59
    {
60
        $item = $this->getGalleryItem($name, 0);
61
        assertNull($item, "File named {$name} was found when it should not be visible");
62
    }
63
64
    /**
65
     * @Then /^I should see the "([^"]*)" form$/
66
     * @param string $id HTML ID of form
67
     */
68
    public function iShouldSeeTheForm($id)
69
    {
70
        /** @var DocumentElement $page */
71
        $page = $this->getSession()->getPage();
72
        $form = $this->retry(function () use ($page, $id) {
73
            return $page->find('css', "form#{$id}");
74
        });
75
        assertNotNull($form, "form with id $id could not be found");
76
        assertTrue($form->isVisible(), "form with id $id is not visible");
77
    }
78
79
    /**
80
     * @Then /^I should see the draft file status flag$/
81
     */
82
    public function iShouldSeeTheDraftFileStatusFlag()
83
    {
84
        $page = $this->getSession()->getPage();
85
        $flag = $page->find('css', '.editor__status-flag');
86
        assertNotNull($flag, "File editor draft status flag could not be found");
87
        assertTrue($flag->isVisible(), "Draft status flag is not visible");
88
    }
89
90
    /**
91
     * @Then /^I should not see the file status flag$/
92
     */
93
    public function iShouldNotSeeTheFileStatusFlag()
94
    {
95
        $page = $this->getSession()->getPage();
96
        $flag = $page->find('css', '.editor__status-flag');
97
        assertNull($flag, "File editor status flag should not be present");
98
    }
99
100
    /**
101
     * @Given /^I click on the latest history item$/
102
     */
103
    public function iClickOnTheLatestHistoryItem()
104
    {
105
        $this->getSession()->wait(
106
            5000,
107
            "window.jQuery && window.jQuery('.file-history__list li').size() > 0"
108
        );
109
110
        $page = $this->getSession()->getPage();
111
112
        $elements = $page->find('css', '.file-history__list li');
113
114
        if (null === $elements) {
115
            throw new \InvalidArgumentException(sprintf('Could not find list item'));
116
        }
117
118
        $elements->click();
119
    }
120
121
    /**
122
     * @Given /^I attach the file "([^"]*)" to dropzone "([^"]*)"$/
123
     * @see MinkContext::attachFileToField()
124
     */
125
    public function iAttachTheFileToDropzone($path, $name)
126
    {
127
        // Get path
128
        $filesPath = $this->getMainContext()->getMinkParameter('files_path');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Behat\Context\ExtendedContextInterface as the method getMinkParameter() does only exist in the following implementations of said interface: Behat\MinkExtension\Context\MinkContext, Behat\MinkExtension\Context\RawMinkContext, SilverStripe\AssetAdmin\...\Context\FeatureContext, SilverStripe\BehatExtens...ext\SilverStripeContext, SilverStripe\Cms\Test\Behaviour\FeatureContext, SilverStripe\Framework\T...ehaviour\FeatureContext, SilverStripe\Siteconfig\...ehaviour\FeatureContext.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
129
        if ($filesPath) {
130
            $fullPath = rtrim(realpath($filesPath), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$path;
131
            if (is_file($fullPath)) {
132
                $path = $fullPath;
133
            }
134
        }
135
136
        assertFileExists($path, "$path does not exist");
137
        // Find field
138
        $selector = "input[type=\"file\"].dz-hidden-input.dz-input-{$name}";
139
140
        /** @var DocumentElement $page */
141
        $page = $this->getSession()->getPage();
142
        $input = $page->find('css', $selector);
143
        assertNotNull($input, "Could not find {$selector}");
144
145
        // Make visible temporarily while attaching
146
        $this->getSession()->executeScript(
147
            <<<EOS
148
window.jQuery('.dz-hidden-input')
149
    .css('visibility', 'visible')
150
    .width(1)
151
    .height(1);
152
EOS
153
        );
154
155
        assert($input->isVisible());
156
        // Attach via html5
157
        $input->attachFile($path);
158
    }
159
160
    /**
161
     * Checks that the message box contains specified text.
162
     *
163
     * @Then /^I should see "(?P<text>(?:[^"]|\\")*)" in the message box$/
164
     */
165
    public function assertMessageBoxContainsText($text)
166
    {
167
        /** @var FeatureContext $mainContext */
168
        $mainContext = $this->getMainContext();
169
        $mainContext
170
            ->assertSession()
171
            ->elementTextContains('css', '.message-box', str_replace('\\"', '"', $text));
172
    }
173
174
    /**
175
     * Helper for finding items in the visible gallery view
176
     *
177
     * @param string $name Title of item
178
     * @param int $timeout
179
     * @return NodeElement
180
     */
181
    protected function getGalleryItem($name, $timeout = 3)
182
    {
183
        /** @var DocumentElement $page */
184
        $page = $this->getSession()->getPage();
185
        return $this->retry(function () use ($page, $name) {
186
            // Find by cell
187
            $cell = $page->find(
188
                'xpath',
189
                "//div[contains(@class, 'gallery-item')]//div[contains(text(), '{$name}')]"
190
            );
191
            if ($cell) {
192
                return $cell;
193
            }
194
            // Find by row
195
            $row = $page->find(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $row is correct as $page->find('xpath', "//...s(text(), '{$name}')]") (which targets Behat\Mink\Element\Element::find()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
196
                'xpath',
197
                "//tr[contains(@class, 'gallery__table-row')]//div[contains(text(), '{$name}')]"
198
            );
199
            if ($row) {
200
                return $row;
201
            }
202
            return null;
203
        }, $timeout);
204
    }
205
206
    /**
207
     * Invoke $try callback for a non-empty result with a given timeout
208
     *
209
     * @param callable $try
210
     * @param int $timeout Number of seconds to retry for
211
     * @return mixed Result of invoking $try, or null if timed out
212
     */
213
    protected function retry($try, $timeout = 3)
214
    {
215
        do {
216
            $result = $try();
217
            if ($result) {
218
                return $result;
219
            }
220
            sleep(1);
221
        } while (--$timeout >= 0);
222
        return null;
223
    }
224
225
    /**
226
     * @Given /^a page "([^"]*)" containing an image "([^"]*)"$/
227
     */
228
    public function aPageContaining($page, $image)
229
    {
230
        // Find or create named image
231
        $fields = $this->prepareFixture(Image::class, $image);
232
        /** @var Image $image */
233
        $image = $this->fixtureFactory->createObject(Image::class, $image, $fields);
234
235
        // Create page
236
        $fields = $this->prepareFixture(Page::class, $page);
237
        $fields = array_merge($fields, [
238
            'Title' => $page,
239
            'Content' => sprintf(
240
                '<p>[image id="%d" width="%d" height="%d"]</p>',
241
                $image->ID,
242
                $image->getWidth(),
243
                $image->getHeight()
244
            ),
245
        ]);
246
        $this->fixtureFactory->createObject(Page::class, $page, $fields);
247
    }
248
}
249