Skip to content

Commit

Permalink
Fix tests and make them more robust when handling asynchronous changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
EreMaijala committed Aug 18, 2023
1 parent d9d1466 commit b21d850
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 52 deletions.
66 changes: 60 additions & 6 deletions module/VuFind/src/VuFindTest/Integration/MinkTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ protected function unFindCss(
try {
$elements = $page->findAll('css', $selector);
if (!isset($elements[$index])) {
$this->assertNull(null);
return;
}
} catch (\Exception $e) {
Expand Down Expand Up @@ -589,28 +590,81 @@ protected function hasElementsMatchingText(Element $page, $selector, $text)
/**
* Wait for a callback to return the expected value
*
* @param mixed $expected Expected value
* @param callable $callback Callback
* @param int $timeout Wait timeout (in ms)
* @param mixed $expected Expected value
* @param callable $callback Callback
* @param callable $assertion Assertion to make
* @param int $timeout Wait timeout (in ms)
*
* @return void
*/
protected function assertEqualsWithTimeout(
protected function assertWithTimeout(
$expected,
callable $callback,
callable $compareFunc,
callable $assertion,
int $timeout = null
) {
$timeout ??= $this->getDefaultTimeout();
$result = null;
$startTime = microtime(true);
while ((microtime(true) - $startTime) * 1000 <= $timeout) {
$result = $callback();
if ($result === $expected) {
if (call_user_func($compareFunc, $expected, $result)) {
break;
}
usleep(100000);
}
$this->assertEquals($expected, $result);
call_user_func($assertion, $expected, $result);
}

/**
* Wait for a callback to return the expected value
*
* @param mixed $expected Expected value
* @param callable $callback Callback
* @param int $timeout Wait timeout (in ms)
*
* @return void
*/
protected function assertEqualsWithTimeout(
$expected,
callable $callback,
int $timeout = null
) {
$this->assertWithTimeout(
$expected,
$callback,
function ($expected, $result): bool {
return $expected === $result;
},
[$this, 'assertEquals'],
$timeout
);
}

/**
* Wait for a callback to return a string containing the expected value
*
* @param string $expected Expected value
* @param callable $callback Callback
* @param int $timeout Wait timeout (in ms)
*
* @return void
*/
protected function assertStringContainsStringWithTimeout(
string $expected,
callable $callback,
int $timeout = null
) {
$this->assertWithTimeout(
$expected,
$callback,
function (string $expected, string $result): bool {
return str_contains($result, $expected);
},
[$this, 'assertStringContainsString'],
$timeout
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

namespace VuFindTest\Mink;

use Behat\Mink\Element\Element;

/**
* Test basic search functionality.
*
Expand All @@ -53,61 +55,99 @@ public function testOutOfBoundsPage()
$session->visit($baseUrl . '&page=1000');
$this->assertEquals($baseUrl . '&page=1', $session->getCurrentUrl());
$page = $session->getPage();
$this->assertMatchesRegularExpression(
"/Showing 1 - 1 results of 1 for search 'id:testbug1', query time: .*/",
$this->assertStringStartsWith(
'Showing 1 - 1 results of 1',
trim($this->findCss($page, '.search-stats')->getText())
);
}

/**
* Test simple top pagination
* Data provider for testDefaultTopPagination
*/
public function topPaginationProvider(): array
{
return [
[false],
[true],
];
}

/**
* Test default top pagination
*
* @dataProvider topPaginationProvider
*
* @return void
*/
public function testSimpleTopPagination(): void
public function testDefaultTopPagination(bool $jsResults): void
{
// Change configuration:
$this->changeConfigs(
[
'searches' => [
'General' => [
'load_results_with_js' => $jsResults,
],
],
]
);

$session = $this->getMinkSession();
$session->visit($this->getVuFindUrl() . '/Search/Results');
$page = $session->getPage();

// No paginator unless configured:
$this->unFindCss($page, '.search-header .pagination');
$this->unFindCss($page, '.search-header .pagination-simple');
// Should never have full pagination:
$this->unFindCss($page, '.pagination-top');

// Enable pagination:
if ($jsResults) {
// Simple paginator by default with JS results:
$this->findCss($page, '.search-header .pagination-simple');
} else {
// No paginator by default without JS results:
$this->unFindCss($page, '.search-header .pagination-simple');
}
}

/**
* Test simple top pagination
*
* @dataProvider topPaginationProvider
*
* @return void
*/
public function testSimpleTopPagination(bool $jsResults): void
{
$config = [
'load_results_with_js' => $jsResults,
];
if (!$jsResults) {
// Enable top paginator:
$config['top_paginator'] = 'simple';
}
$this->changeConfigs(
[
'searches' => [
'General' => [
'top_paginator' => 'simple',
],
'General' => $config,
],
]
);

$session = $this->getMinkSession();
$session->visit($this->getVuFindUrl() . '/Search/Results');
$this->assertStringContainsString(
'Showing 1 - 20 results',
$this->findCss($page, '.search-stats')->getText()
);
$page = $session->getPage();
$this->assertShowingResults($page, '1 - 20');

// No prev page on first page:
$this->unFindCss($page, '.search-header .pagination-simple .page-prev');

$secondPage = $this->findCss($page, '.search-header .pagination-simple .page-next');
$secondPage->click();
$this->waitForPageLoad($page);
$this->assertStringContainsString(
'Showing 21 - 40 results',
$this->findCss($page, '.search-stats')->getText()
);
$this->assertShowingResults($page, '21 - 40');
$this->scrollToResults();

// Prev page now present, click it:
$this->clickCss($page, '.search-header .pagination-simple .page-prev');
$this->waitForPageLoad($page);
$this->assertStringContainsString(
'Showing 1 - 20 results',
$this->findCss($page, '.search-stats')->getText()
);
$this->assertShowingResults($page, '1 - 20');
}

/**
Expand All @@ -117,13 +157,6 @@ public function testSimpleTopPagination(): void
*/
public function testFullTopPagination(): void
{
$session = $this->getMinkSession();
$session->visit($this->getVuFindUrl() . '/Search/Results');
$page = $session->getPage();

// No paginator unless configured:
$this->unFindCss($page, '.pagination-top');

// Enable pagination:
$this->changeConfigs(
[
Expand All @@ -135,29 +168,25 @@ public function testFullTopPagination(): void
]
);

$session = $this->getMinkSession();
$session->visit($this->getVuFindUrl() . '/Search/Results');
$this->assertStringContainsString(
'Showing 1 - 20 results',
$this->findCss($page, '.search-stats')->getText()
);
$page = $session->getPage();

$session->visit($this->getVuFindUrl() . '/Search/Results');
$this->assertShowingResults($page, '1 - 20');

$this->assertEquals('1', $this->findCss($page, '.pagination-top li.active')->getText());
$secondPage = $this->findCss($page, '.pagination-top li', null, 1);
$secondPage->find('css', 'a')->click();
$this->waitForPageLoad($page);

$this->assertStringContainsString(
'Showing 21 - 40 results',
$this->findCss($page, '.search-stats')->getText()
);
$this->assertShowingResults($page, '21 - 40');
$this->assertEquals('2', $this->findCss($page, '.pagination-top li.active')->getText());

// First page now present, click it:
$firstPage = $this->findCss($page, '.pagination-top li');
$firstPage->find('css', 'a')->click();
$this->assertStringContainsString(
'Showing 1 - 20 results',
$this->findCss($page, '.search-stats')->getText()
);
$this->scrollToResults();
$this->clickCss($page, '.pagination-top li a');
$this->assertShowingResults($page, '1 - 20');
$this->assertEquals('1', $this->findCss($page, '.pagination-top li.active')->getText());
}

Expand All @@ -179,4 +208,34 @@ public function testBottomPagination(): void

$this->assertEquals('2', $this->findCss($page, '.pagination li.active')->getText());
}

/**
* Check that correct result range is being displayed
*
* @param Element $page Page
* @param string $results Result range (e.g. '1 - 20')
*
* @return void
*/
protected function assertShowingResults(Element $page, string $results): void
{
$this->assertStringContainsStringWithTimeout(
"Showing $results results",
function () use ($page): string {
return $this->findCss($page, '.search-stats')->getText();
}
);
}

/**
* Scroll to results immediately to avoid elements from moving around while we click them
*
* @return void
*/
protected function scrollToResults(): void
{
$this->getMinkSession()->executeScript(
'typeof VuFind.search !== "undefined" && VuFind.search.scrollToResults("instant")'
);
}
}

0 comments on commit b21d850

Please sign in to comment.