GridWebContext   B
last analyzed

Complexity

Total Complexity 48

Size/Duplication

Total Lines 351
Duplicated Lines 4.56 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 0
Metric Value
wmc 48
lcom 2
cbo 7
dl 16
loc 351
rs 8.4864
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 6 1
A toggleBatch() 0 6 2
A selectBatch() 0 4 1
A selectBatchAll() 0 11 1
A followSortingLink() 0 11 2
A followColumnActionLink() 0 11 1
A waitFilters() 0 6 2
A waitFiltersRefresh() 0 4 1
A assertGrid() 0 5 1
A assertHeaders() 8 8 3
A assertHeader() 0 8 1
A assertBatchesState() 0 12 3
A assertBody() 0 6 2
A assertRow() 8 8 3
A assertColumnCells() 0 9 3
A assertCell() 0 14 1
A assertSorting() 0 21 2
A hastBatch() 0 10 2
A findBatch() 0 20 2
A findHeaderIndex() 0 6 1
A findHeader() 0 11 2
D findCell() 0 36 10
A findGrid() 0 11 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like GridWebContext 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 GridWebContext, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the Lug package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Lug\Bundle\GridBundle\Behat\Context;
13
14
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
15
use Behat\Mink\Driver\Selenium2Driver;
16
use Behat\Mink\Element\NodeElement;
17
use Behat\MinkExtension\Context\MinkAwareContext;
18
use Lug\Component\Behat\Context\AjaxContext;
19
use Lug\Component\Behat\Dictionary\MinkDictionary;
20
21
/**
22
 * @author GeLo <[email protected]>
23
 */
24
class GridWebContext implements MinkAwareContext
25
{
26
    use MinkDictionary;
27
28
    /**
29
     * @var AjaxContext
30
     */
31
    private $ajaxContext;
32
33
    /**
34
     * @BeforeScenario
35
     */
36
    public function init(BeforeScenarioScope $scope)
37
    {
38
        $environment = $scope->getEnvironment();
39
40
        $this->ajaxContext = $environment->getContext(AjaxContext::class);
41
    }
42
43
    public function toggleBatch()
44
    {
45
        $batch = $this->findBatch();
46
47
        $batch->isChecked() ? $batch->check() : $batch->uncheck();
48
    }
49
50
    /**
51
     * @param string|null $cell
52
     */
53
    public function selectBatch($cell = null)
54
    {
55
        $this->findBatch($cell)->check();
56
    }
57
58
    public function selectBatchAll()
59
    {
60
        $xpath = '//input[@id="grid_batch_all"]';
61
62
        \PHPUnit_Framework_Assert::assertNotNull(
63
            $node = $this->findGrid()->find('xpath', $xpath),
64
            'The grid "all" batch could not be found.'
65
        );
66
67
        $node->check();
68
    }
69
70
    /**
71
     * @param string|int $header
72
     * @param string     $sorting
73
     */
74
    public function followSortingLink($header, $sorting)
75
    {
76
        $xpath = '//a[@title="'.($sorting === 'ASC' ? 'Ascending' : 'Descending').'"]';
77
78
        \PHPUnit_Framework_Assert::assertNotNull(
79
            $node = $this->findHeader($header)->find('xpath', $xpath),
80
            sprintf('The grid column sorting link "%s" (%s) could not be found.', $header, $sorting)
81
        );
82
83
        $node->click();
84
    }
85
86
    /**
87
     * @param string $cell
88
     * @param string $link
89
     */
90
    public function followColumnActionLink($cell, $link)
91
    {
92
        $xpath = '/../td[last()]//*[text()[contains(., "'.$link.'")]]';
93
94
        \PHPUnit_Framework_Assert::assertNotNull(
95
            $node = $this->findCell(null, null, $cell)->find('xpath', $xpath),
96
            sprintf('The column action link "%s" of the cell "%s" could not be found.', $link, $cell)
97
        );
98
99
        $node->click();
100
    }
101
102
    public function waitFilters()
103
    {
104
        if ($this->getDriver() instanceof Selenium2Driver) {
105
            $this->getSession()->wait('10000', '$(\'#grid_modal h4\').is(\':visible\')');
106
        }
107
    }
108
109
    public function waitFiltersRefresh()
110
    {
111
        $this->ajaxContext->waitAjax();
112
    }
113
114
    /**
115
     * @param mixed[] $rows
116
     */
117
    public function assertGrid(array $rows)
118
    {
119
        $this->assertHeaders($rows[0]);
120
        $this->assertBody(array_slice($rows, 1));
121
    }
122
123
    /**
124
     * @param string[] $columns
125
     */
126 View Code Duplication
    public function assertHeaders(array $columns)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
127
    {
128
        $offset = $this->hastBatch() ? 2 : 1;
129
130
        foreach ($columns as $column => $value) {
131
            $this->assertHeader($column + $offset, $value);
132
        }
133
    }
134
135
    /**
136
     * @param string|int $header
137
     * @param string     $value
138
     */
139
    public function assertHeader($header, $value)
140
    {
141
        \PHPUnit_Framework_Assert::assertContains(
142
            $value,
143
            $text = $this->findHeader($header)->getText(),
144
            sprintf('The grid column header "%s" does not contain "%s", got "%s".', $header, $value, $text)
145
        );
146
    }
147
148
    /**
149
     * @param bool $checked
150
     */
151
    public function assertBatchesState($checked)
152
    {
153
        $xpath = '/tr/td[1]/input';
154
155
        foreach ($this->findGrid()->findAll('xpath', $xpath) as $batch) {
156
            \PHPUnit_Framework_Assert::assertSame(
157
                $checked,
158
                $batch->isChecked(),
159
                sprintf('The grid batch "%s" should %s checked.', $batch->getValue(), $checked ? 'be' : 'not be')
160
            );
161
        }
162
    }
163
164
    /**
165
     * @param string[][] $rows
166
     */
167
    public function assertBody(array $rows)
168
    {
169
        foreach ($rows as $row => $columns) {
170
            $this->assertRow($row + 1, $columns);
171
        }
172
    }
173
174
    /**
175
     * @param int      $row
176
     * @param string[] $columns
177
     */
178 View Code Duplication
    public function assertRow($row, array $columns)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
    {
180
        $offset = $this->hastBatch() ? 2 : 1;
181
182
        foreach ($columns as $column => $value) {
183
            $this->assertCell($row, $column + $offset, $value);
184
        }
185
    }
186
187
    /**
188
     * @param string[] $header
189
     * @param string[] $cells
190
     */
191
    public function assertColumnCells($header, array $cells)
192
    {
193
        $column = $this->findHeaderIndex($header);
0 ignored issues
show
Documentation introduced by
$header is of type array<integer,string>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
194
        $offset = $this->hastBatch() ? 1 : 0;
195
196
        foreach ($cells as $row => $value) {
197
            $this->assertCell($row + 1, $column + $offset, $value);
198
        }
199
    }
200
201
    /**
202
     * @param int    $row
203
     * @param int    $column
204
     * @param string $value
205
     */
206
    public function assertCell($row, $column, $value)
207
    {
208
        \PHPUnit_Framework_Assert::assertContains(
209
            $value,
210
            $text = $this->findCell($row, $column)->getText(),
211
            sprintf(
212
                'The grid column body "%s" does not contain "%s at position %d, %d".',
213
                $text,
214
                $value,
215
                $row,
216
                $column
217
            )
218
        );
219
    }
220
221
    /**
222
     * @param string $header
223
     * @param string $sort
224
     */
225
    public function assertSorting($header, $sort)
226
    {
227
        $index = $this->findHeaderIndex($header);
228
229
        $values = $sortedValues = array_map(function (NodeElement $node) {
230
            return $node->getText();
231
        }, $this->findCell(null, $index));
232
233
        array_multisort($sortedValues, $sort === 'ASC' ? SORT_ASC : SORT_DESC);
234
235
        \PHPUnit_Framework_Assert::assertSame(
236
            $sortedValues,
237
            $values,
238
            sprintf(
239
                'The grid sorting does not match for the column "%s". Expected "%s", got "%s".',
240
                $header,
241
                json_encode($sortedValues),
242
                json_encode($values)
243
            )
244
        );
245
    }
246
247
    /**
248
     * @return bool
249
     */
250
    public function hastBatch()
251
    {
252
        try {
253
            $this->findBatch();
254
255
            return true;
256
        } catch (\PHPUnit_Framework_ExpectationFailedException $e) {
257
            return false;
258
        }
259
    }
260
261
    /**
262
     * @param string|null $cell
263
     *
264
     * @return NodeElement
265
     */
266
    public function findBatch($cell = null)
267
    {
268
        if ($cell === null) {
269
            \PHPUnit_Framework_Assert::assertNotNull(
270
                $batch = $this->findHeader(1)->find('xpath', '/input'),
271
                'The grid toggle batch checkbox could not be found.'
272
            );
273
274
            return $batch;
275
        }
276
277
        $xpath = '/../td[1]/input';
278
279
        \PHPUnit_Framework_Assert::assertNotNull(
280
            $batch = $this->findCell(null, null, $cell)->find('xpath', $xpath),
281
            sprintf('The grid column batch checkbox of the cell "%s" could not be found.', $cell)
282
        );
283
284
        return $batch;
285
    }
286
287
    /**
288
     * @param string $header
289
     *
290
     * @return int
291
     */
292
    public function findHeaderIndex($header)
293
    {
294
        $xpath = $this->findHeader($header)->getXpath().'/preceding::*';
295
296
        return count($this->getPage()->findAll('xpath', $xpath)) + 1;
297
    }
298
299
    /**
300
     * @param string|int $header
301
     *
302
     * @return NodeElement
303
     */
304
    public function findHeader($header)
305
    {
306
        $xpath = '/thead/tr/th'.(is_int($header) ? '['.$header.']' : '[contains(text(), "'.$header.'")]');
307
308
        \PHPUnit_Framework_Assert::assertNotNull(
309
            $node = $this->findGrid()->find('xpath', $xpath),
310
            sprintf('The grid header "%s" could not be found.', $header)
311
        );
312
313
        return $node;
314
    }
315
316
    /**
317
     * @param int|null    $row
318
     * @param int|null    $column
319
     * @param string|null $value
320
     *
321
     * @return NodeElement|NodeElement[]
322
     */
323
    public function findCell($row = null, $column = null, $value = null)
324
    {
325
        $rowXPath = $row;
326
        $columnXPath = $column;
327
        $valueXPath = $value;
328
329
        if ($row !== null) {
330
            $rowXPath = '['.$row.']';
331
        }
332
333
        if ($column !== null) {
334
            $columnXPath = '['.$column.']';
335
        }
336
337
        if ($value !== null) {
338
            $valueXPath = '[contains(text(), "'.$value.'")]';
339
        }
340
341
        $xpath = '/tbody/tr'.$rowXPath.'/td'.$columnXPath.$valueXPath;
342
343
        if ($value !== null || ($row !== null && $column !== null)) {
344
            \PHPUnit_Framework_Assert::assertNotNull(
345
                $cell = $this->findGrid()->find('xpath', $xpath),
346
                sprintf(
347
                    'The grid cell could not be found (row: %s, column: %s, value: %s).',
348
                    $row !== null ? $row : 'none',
349
                    $column !== null ? $column : 'none',
350
                    $value !== null ? $value : 'none'
351
                )
352
            );
353
354
            return $cell;
355
        }
356
357
        return $this->findGrid()->findAll('xpath', $xpath);
358
    }
359
360
    /**
361
     * @return NodeElement
362
     */
363
    public function findGrid()
364
    {
365
        $xpath = '//section[contains(@class, "content")]//table';
366
367
        \PHPUnit_Framework_Assert::assertNotNull(
368
            $grid = $this->getPage()->find('xpath', $xpath),
369
            'The grid could not be found.'
370
        );
371
372
        return $grid;
373
    }
374
}
375